From 8b38e6f429f05c590622d907d3d47ea64a408265 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jul 2020 10:37:06 -0700 Subject: [PATCH 1/6] update dataset comments --- data/coco.yaml | 6 +++--- data/coco128.yaml | 12 ++++++------ data/get_coco2017.sh | 5 +++-- data/get_voc.sh | 3 ++- data/voc.yaml | 9 +++++---- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/data/coco.yaml b/data/coco.yaml index 291149aeed60..26f2db9e9761 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -1,13 +1,13 @@ # COCO 2017 dataset http://cocodataset.org # Download command: bash yolov5/data/get_coco2017.sh -# Train command: python train.py --data ./data/coco.yaml -# Dataset should be placed next to yolov5 folder: +# Train command: python train.py --data coco.yaml +# Default dataset location is next to /yolov5: # /parent_folder # /coco # /yolov5 -# train and val datasets (image directory or *.txt file with image paths) +# 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 # 118k images val: ../coco/val2017.txt # 5k images test: ../coco/test-dev2017.txt # 20k images for submission to https://competitions.codalab.org/competitions/20794 diff --git a/data/coco128.yaml b/data/coco128.yaml index 2b6184890cdb..a7ac848195c3 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,15 +1,15 @@ # COCO 2017 dataset http://cocodataset.org - first 128 training images -# Download command: python -c "from yolov5.utils.google_utils import gdrive_download; gdrive_download('1n_oKgR81BJtqk75b00eAjdv03qVCQn2f','coco128.zip')" -# Train command: python train.py --data ./data/coco128.yaml -# Dataset should be placed next to yolov5 folder: +# Download command: python -c "from yolov5.utils.google_utils import *; gdrive_download('1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', 'coco128.zip')" +# Train command: python train.py --data coco128.yaml +# Default dataset location is next to /yolov5: # /parent_folder # /coco128 # /yolov5 -# train and val datasets (image directory or *.txt file with image paths) -train: ../coco128/images/train2017/ -val: ../coco128/images/train2017/ +# 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 diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh index 03b2c7e89301..aa031dfb6a4e 100755 --- a/data/get_coco2017.sh +++ b/data/get_coco2017.sh @@ -1,12 +1,13 @@ #!/bin/bash # COCO 2017 dataset http://cocodataset.org # Download command: bash yolov5/data/get_coco2017.sh -# Train command: python train.py --data ./data/coco.yaml -# Dataset should be placed next to yolov5 folder: +# Train command: python train.py --data coco.yaml +# Default dataset location is next to /yolov5: # /parent_folder # /coco # /yolov5 + # Download labels from Google Drive, accepting presented query filename="coco2017labels.zip" fileid="1cXZR_ckHki6nddOmcysCuuJFM--T-Q6L" diff --git a/data/get_voc.sh b/data/get_voc.sh index b7e66d003133..3eaad6b56efb 100644 --- a/data/get_voc.sh +++ b/data/get_voc.sh @@ -1,11 +1,12 @@ # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC/ # Download command: bash ./data/get_voc.sh # Train command: python train.py --data voc.yaml -# Dataset should be placed next to yolov5 folder: +# Default dataset location is next to /yolov5: # /parent_folder # /VOC # /yolov5 + start=`date +%s` # handle optional download dir diff --git a/data/voc.yaml b/data/voc.yaml index efe22308ad47..12d05fd9d143 100644 --- a/data/voc.yaml +++ b/data/voc.yaml @@ -1,14 +1,15 @@ # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC/ # Download command: bash ./data/get_voc.sh # Train command: python train.py --data voc.yaml -# Dataset should be placed next to yolov5 folder: +# Default dataset location is next to /yolov5: # /parent_folder # /VOC # /yolov5 -# train and val datasets (image directory or *.txt file with image paths) -train: ../VOC/images/train/ -val: ../VOC/images/val/ + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: ../VOC/images/train/ # 16551 images +val: ../VOC/images/val/ # 4952 images # number of classes nc: 20 From 41ff83a98d3030d920b184c3b87cc24270bbd611 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jul 2020 12:18:00 -0700 Subject: [PATCH 2/6] update torch_utils.py to FP16 EMA --- utils/torch_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 429351ab3a24..49d08ba7b4b7 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -195,6 +195,8 @@ class ModelEMA: 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) for p in self.ema.parameters(): From 0afbb8d49829becef83707ab76f9e7dc9106436b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jul 2020 13:25:58 -0700 Subject: [PATCH 3/6] update test.py model.half() --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index ef97d26c1942..f819bae1c06e 100644 --- a/test.py +++ b/test.py @@ -41,9 +41,9 @@ def test(data, # model = nn.DataParallel(model) # Half - half = device.type != 'cpu' and torch.cuda.device_count() == 1 # half precision only supported on single-GPU + half = device.type != 'cpu' # half precision only supported on CUDA if half: - model.half() # to FP16 + model.half() # Configure model.eval() From eae33303d673133fa310ca2431f335de11133fe1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jul 2020 14:14:51 -0700 Subject: [PATCH 4/6] update datasets.py LoadImages() path improvements and Mixup --- utils/datasets.py | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index d0349422b67c..e88ce769923e 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -68,35 +68,37 @@ def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=Fa class LoadImages: # for inference def __init__(self, path, img_size=640): - 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] + p = str(Path(path)) # os-agnostic + p = os.path.abspath(p) # absolute path + if os.path.isdir(p): + files = sorted(glob.glob(os.path.join(p, '*.*'))) + elif os.path.isfile(p): + files = [p] + else: + raise Exception('ERROR: %s does not exist' % p) 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) + 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] @@ -107,7 +109,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] @@ -115,14 +117,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] @@ -140,7 +142,7 @@ 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 @@ -470,6 +472,13 @@ def __getitem__(self, index): img, labels = load_mosaic(self, index) shapes = None + # MixUp https://arxiv.org/pdf/1710.09412.pdf + # if random.random() < 0.5: + # img2, labels2 = load_mosaic(self, random.randint(0, len(self.labels) - 1)) + # r = np.random.beta(0.3, 0.3) # mixup ratio, alpha=beta=0.3 + # 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) From 8412d44dced167353b914b798f86c72f7f89a058 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jul 2020 14:22:15 -0700 Subject: [PATCH 5/6] update datasets.py to add detect.py --source glob_command feature --- utils/datasets.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index e88ce769923e..cc5411f4e324 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -70,10 +70,12 @@ class LoadImages: # for inference def __init__(self, path, img_size=640): p = str(Path(path)) # os-agnostic p = os.path.abspath(p) # absolute path - if os.path.isdir(p): - files = sorted(glob.glob(os.path.join(p, '*.*'))) + if '*' in p: + files = sorted(glob.glob(p)) # glob + elif os.path.isdir(p): + files = sorted(glob.glob(os.path.join(p, '*.*'))) # dir elif os.path.isfile(p): - files = [p] + files = [p] # files else: raise Exception('ERROR: %s does not exist' % p) From e169edfcf54797456e11c2d0e5c3d43b64beadb8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jul 2020 14:28:19 -0700 Subject: [PATCH 6/6] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e066c45acd59..7de8d5e7a789 100755 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This repository represents Ultralytics open-source research into future object d | [YOLOv5m](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 43.4 | 43.4 | 62.4 | 3.0ms | 333 || 21.8M | 39.4B | [YOLOv5l](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 46.6 | 46.7 | 65.4 | 3.9ms | 256 || 47.8M | 88.1B | [YOLOv5x](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | **48.4** | **48.4** | **66.9** | 6.1ms | 164 || 89.0M | 166.4B -| [YOLOv3-SPP](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 45.6 | 45.5 | 65.2 | 4.5ms | 222 || 63.0M | 118.0B +| [YOLOv3-SPP](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 45.6 | 45.5 | 65.2 | 4.5ms | 222 || 63.0M | 118.0B ** APtest denotes COCO [test-dev2017](http://cocodataset.org/#upload) server results, all other AP results in the table denote val2017 accuracy. @@ -54,10 +54,11 @@ $ pip install -U -r requirements.txt Inference can be run on most common media formats. Model [checkpoints](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) are downloaded automatically if available. Results are saved to `./inference/output`. ```bash -$ python detect.py --source file.jpg # image +$ python detect.py --source 0 # webcam + file.jpg # image file.mp4 # video - ./dir # directory - 0 # webcam + path/ # directory + path/*.jpg # glob rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa # rtsp stream http://112.50.243.8/PLTV/88888888/224/3221225900/1.m3u8 # http stream ```