From 70427579b83ebc9760bbbbd97dbb04ce8faa73d0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Jan 2023 14:34:51 +0100 Subject: [PATCH] COCO8 and COCO8-seg Pytest and CI updates (#307) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: RangiLyu --- .github/workflows/ci.yaml | 17 +-- .gitignore | 1 + docs/index.md | 3 - mkdocs.yml | 5 +- setup.py | 8 +- tests/test_cli.py | 8 +- tests/test_engine.py | 51 ++++----- tests/test_python.py | 8 +- ultralytics/nn/modules.py | 2 +- ultralytics/yolo/data/datasets/coco8-seg.yaml | 101 ++++++++++++++++++ ultralytics/yolo/data/datasets/coco8.yaml | 101 ++++++++++++++++++ ultralytics/yolo/utils/loss.py | 1 + ultralytics/yolo/v8/__init__.py | 7 +- 13 files changed, 254 insertions(+), 59 deletions(-) create mode 100644 ultralytics/yolo/data/datasets/coco8-seg.yaml create mode 100644 ultralytics/yolo/data/datasets/coco8.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 28db853..123d9d7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,8 +8,8 @@ on: branches: [main] pull_request: branches: [main] - # schedule: - # - cron: '0 0 * * *' # runs at 00:00 UTC every day + schedule: + - cron: '0 0 * * *' # runs at 00:00 UTC every day jobs: Tests: @@ -54,7 +54,7 @@ jobs: pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu fi # pip install ultralytics (production) - pip install . + pip install -e . pytest shell: bash # for Windows compatibility - name: Check environment run: | @@ -78,21 +78,21 @@ jobs: from ultralytics import hub, yolo key = os.environ['APIKEY'] print(ultralytics.__version__) - # ultralytics.checks() + ultralytics.checks() # ultralytics.reset_model(key) # reset trained model # ultralytics.start(key) # train model - name: Test detection shell: bash # for Windows compatibility run: | - yolo task=detect mode=train model=yolov8n.yaml data=coco128.yaml epochs=1 imgsz=32 + yolo task=detect mode=train model=yolov8n.yaml data=coco8.yaml epochs=1 imgsz=32 yolo task=detect mode=val model=runs/detect/train/weights/last.pt imgsz=32 yolo task=detect mode=predict model=runs/detect/train/weights/last.pt imgsz=32 source=ultralytics/assets/bus.jpg yolo mode=export model=runs/detect/train/weights/last.pt imgsz=32 format=torchscript - name: Test segmentation shell: bash # for Windows compatibility run: | - yolo task=segment mode=train model=yolov8n-seg.yaml data=coco128-seg.yaml epochs=1 imgsz=32 - yolo task=segment mode=val model=runs/segment/train/weights/last.pt data=coco128-seg.yaml imgsz=32 + yolo task=segment mode=train model=yolov8n-seg.yaml data=coco8-seg.yaml epochs=1 imgsz=32 + yolo task=segment mode=val model=runs/segment/train/weights/last.pt data=coco8-seg.yaml imgsz=32 yolo task=segment mode=predict model=runs/segment/train/weights/last.pt imgsz=32 source=ultralytics/assets/bus.jpg yolo mode=export model=runs/segment/train/weights/last.pt imgsz=32 format=torchscript - name: Test classification @@ -102,3 +102,6 @@ jobs: yolo task=classify mode=val model=runs/classify/train/weights/last.pt data=mnist160 imgsz=32 yolo task=classify mode=predict model=runs/classify/train/weights/last.pt imgsz=32 source=ultralytics/assets/bus.jpg yolo mode=export model=runs/classify/train/weights/last.pt imgsz=32 format=torchscript + - name: Pytest tests + shell: bash # for Windows compatibility + run: pytest tests \ No newline at end of file diff --git a/.gitignore b/.gitignore index ef69c30..ee44a4f 100644 --- a/.gitignore +++ b/.gitignore @@ -148,3 +148,4 @@ wandb/ *_saved_model/ *_web_model/ *_openvino_model/ +*_paddle_model/ diff --git a/docs/index.md b/docs/index.md index 6bc16c7..3fa3b5f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,11 +10,8 @@ Open In Colab Open In Kaggle
-
-# Welcome to Ultralytics YOLOv8 - Welcome to the Ultralytics YOLOv8 documentation landing page! [Ultralytics YOLOv8](https://github.com/ultralytics/ultralytics) is the latest version of the YOLO (You Only Look Once) object detection and image segmentation model developed by [Ultralytics](https://ultralytics.com). This page diff --git a/mkdocs.yml b/mkdocs.yml index bacf144..6add0f1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: Ultralytics Docs +site_name: Ultralytics YOLOv8 Docs repo_url: https://github.com/ultralytics/ultralytics edit_uri: https://github.com/ultralytics/ultralytics/tree/main/docs repo_name: ultralytics/ultralytics @@ -6,7 +6,7 @@ repo_name: ultralytics/ultralytics theme: name: "material" logo: https://github.com/ultralytics/assets/raw/main/logo/Ultralytics-logomark-white.png - favicon: assets/favicon.ico + favicon: https://github.com/ultralytics/assets/raw/main/logo/favicon-yolo.ico font: text: Roboto @@ -75,6 +75,7 @@ plugins: # Primary navigation nav: + - Home: index.md - Quickstart: quickstart.md - Tasks: - Detection: tasks/detection.md diff --git a/setup.py b/setup.py index a5d13d9..05f25ad 100644 --- a/setup.py +++ b/setup.py @@ -8,13 +8,13 @@ from setuptools import find_packages, setup # Settings FILE = Path(__file__).resolve() -ROOT = FILE.parent # root directory -README = (ROOT / "README.md").read_text(encoding="utf-8") -REQUIREMENTS = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements((ROOT / 'requirements.txt').read_text())] +PARENT = FILE.parent # root directory +README = (PARENT / "README.md").read_text(encoding="utf-8") +REQUIREMENTS = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements((PARENT / 'requirements.txt').read_text())] def get_version(): - file = ROOT / 'ultralytics/__init__.py' + file = PARENT / 'ultralytics/__init__.py' return re.search(r'^__version__ = [\'"]([^\'"]*)[\'"]', file.read_text(), re.M)[1] diff --git a/tests/test_cli.py b/tests/test_cli.py index 35d6d4e..8259540 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -15,11 +15,11 @@ def test_checks(): # Train checks --------------------------------------------------------------------------------------------------------- def test_train_det(): - os.system(f'yolo mode=train task=detect model={CFG}.yaml data=coco128.yaml imgsz=32 epochs=1') + os.system(f'yolo mode=train task=detect model={CFG}.yaml data=coco8.yaml imgsz=32 epochs=1') def test_train_seg(): - os.system(f'yolo mode=train task=segment model={CFG}-seg.yaml data=coco128-seg.yaml imgsz=32 epochs=1') + os.system(f'yolo mode=train task=segment model={CFG}-seg.yaml data=coco8-seg.yaml imgsz=32 epochs=1') def test_train_cls(): @@ -28,11 +28,11 @@ def test_train_cls(): # Val checks ----------------------------------------------------------------------------------------------------------- def test_val_detect(): - os.system(f'yolo mode=val task=detect model={MODEL}.pt data=coco128.yaml imgsz=32 epochs=1') + os.system(f'yolo mode=val task=detect model={MODEL}.pt data=coco8.yaml imgsz=32 epochs=1') def test_val_segment(): - os.system(f'yolo mode=val task=segment model={MODEL}-seg.pt data=coco128-seg.yaml imgsz=32 epochs=1') + os.system(f'yolo mode=val task=segment model={MODEL}-seg.pt data=coco8-seg.yaml imgsz=32 epochs=1') def test_val_classify(): diff --git a/tests/test_engine.py b/tests/test_engine.py index 6845b48..c74dc7a 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -1,6 +1,5 @@ # Ultralytics YOLO 🚀, GPL-3.0 license -from ultralytics import YOLO from ultralytics.yolo.configs import get_config from ultralytics.yolo.utils import DEFAULT_CONFIG, ROOT from ultralytics.yolo.v8 import classify, detect, segment @@ -13,9 +12,10 @@ SOURCE = ROOT / "assets" def test_detect(): - overrides = {"data": "coco128.yaml", "model": CFG_DET, "imgsz": 32, "epochs": 1, "save": False} - CFG.data = "coco128.yaml" - # trainer + overrides = {"data": "coco8.yaml", "model": CFG_DET, "imgsz": 32, "epochs": 1, "save": False} + CFG.data = "coco8.yaml" + + # Trainer trainer = detect.DetectionTrainer(overrides=overrides) trainer.train() trained_model = trainer.best @@ -24,12 +24,10 @@ def test_detect(): val = detect.DetectionValidator(args=CFG) val(model=trained_model) - # predictor - pred = detect.DetectionPredictor(overrides={"imgsz": [640, 640]}) - i = 0 - for _ in pred(source=SOURCE, model="yolov8n.pt", return_outputs=True): - i += 1 - assert i == 2, "predictor test failed" + # Predictor + pred = detect.DetectionPredictor(overrides={"imgsz": [64, 64]}) + result = pred(source=SOURCE, model="yolov8n.pt", return_outputs=True) + assert len(list(result)), "predictor test failed" overrides["resume"] = trainer.last trainer = detect.DetectionTrainer(overrides=overrides) @@ -43,11 +41,11 @@ def test_detect(): def test_segment(): - overrides = {"data": "coco128-seg.yaml", "model": CFG_SEG, "imgsz": 32, "epochs": 1, "save": False} - CFG.data = "coco128-seg.yaml" + overrides = {"data": "coco8-seg.yaml", "model": CFG_SEG, "imgsz": 32, "epochs": 1, "save": False} + CFG.data = "coco8-seg.yaml" CFG.v5loader = False + # YOLO(CFG_SEG).train(**overrides) # works - # YOLO(CFG_SEG).train(**overrides) # This works # trainer trainer = segment.SegmentationTrainer(overrides=overrides) trainer.train() @@ -57,14 +55,12 @@ def test_segment(): val = segment.SegmentationValidator(args=CFG) val(model=trained_model) - # predictor - pred = segment.SegmentationPredictor(overrides={"imgsz": [640, 640]}) - i = 0 - for _ in pred(source=SOURCE, model="yolov8n-seg.pt", return_outputs=True): - i += 1 - assert i == 2, "predictor test failed" + # Predictor + pred = segment.SegmentationPredictor(overrides={"imgsz": [64, 64]}) + result = pred(source=SOURCE, model="yolov8n-seg.pt", return_outputs=True) + assert len(list(result)) == 2, "predictor test failed" - # test resume + # Test resume overrides["resume"] = trainer.last trainer = segment.SegmentationTrainer(overrides=overrides) try: @@ -81,8 +77,9 @@ def test_classify(): CFG.data = "mnist160" CFG.imgsz = 32 CFG.batch = 64 - # YOLO(CFG_SEG).train(**overrides) # This works - # trainer + # YOLO(CFG_SEG).train(**overrides) # works + + # Trainer trainer = classify.ClassificationTrainer(overrides=overrides) trainer.train() trained_model = trainer.best @@ -91,9 +88,7 @@ def test_classify(): val = classify.ClassificationValidator(args=CFG) val(model=trained_model) - # predictor - pred = classify.ClassificationPredictor(overrides={"imgsz": [640, 640]}) - i = 0 - for _ in pred(source=SOURCE, model=trained_model, return_outputs=True): - i += 1 - assert i == 2, "predictor test failed" + # Predictor + pred = classify.ClassificationPredictor(overrides={"imgsz": [64, 64]}) + result = pred(source=SOURCE, model=trained_model, return_outputs=True) + assert len(list(result)) == 2, "predictor test failed" diff --git a/tests/test_python.py b/tests/test_python.py index 13755e3..7faa3e2 100644 --- a/tests/test_python.py +++ b/tests/test_python.py @@ -37,18 +37,18 @@ def test_predict_dir(): def test_val(): model = YOLO(MODEL) - model.val(data="coco128.yaml", imgsz=32) + model.val(data="coco8.yaml", imgsz=32) def test_train_scratch(): model = YOLO(CFG) - model.train(data="coco128.yaml", epochs=1, imgsz=32) + model.train(data="coco8.yaml", epochs=1, imgsz=32) model(SOURCE) def test_train_pretrained(): model = YOLO(MODEL) - model.train(data="coco128.yaml", epochs=1, imgsz=32) + model.train(data="coco8.yaml", epochs=1, imgsz=32) model(SOURCE) @@ -102,7 +102,7 @@ def test_all_model_yamls(): def test_workflow(): model = YOLO(MODEL) - model.train(data="coco128.yaml", epochs=1, imgsz=32) + model.train(data="coco8.yaml", epochs=1, imgsz=32) model.val() model.predict(SOURCE) model.export(format="onnx", opset=12) # export a model to ONNX format diff --git a/ultralytics/nn/modules.py b/ultralytics/nn/modules.py index 2d3435f..9cba6ff 100644 --- a/ultralytics/nn/modules.py +++ b/ultralytics/nn/modules.py @@ -82,7 +82,7 @@ class ConvTranspose(nn.Module): class DFL(nn.Module): - # DFL module + # Integral module of Distribution Focal Loss (DFL) proposed in Generalized Focal Loss https://ieeexplore.ieee.org/document/9792391 def __init__(self, c1=16): super().__init__() self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False) diff --git a/ultralytics/yolo/data/datasets/coco8-seg.yaml b/ultralytics/yolo/data/datasets/coco8-seg.yaml new file mode 100644 index 0000000..54172ee --- /dev/null +++ b/ultralytics/yolo/data/datasets/coco8-seg.yaml @@ -0,0 +1,101 @@ +# Ultralytics YOLO 🚀, GPL-3.0 license +# COCO8-seg dataset (first 8 images from COCO train2017) by Ultralytics +# Example usage: python train.py --data coco8-seg.yaml +# parent +# ├── yolov5 +# └── datasets +# └── coco8-seg ← downloads here (1 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/coco8-seg # dataset root dir +train: images/train # train images (relative to 'path') 4 images +val: images/val # val images (relative to 'path') 4 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/coco8-seg.zip \ No newline at end of file diff --git a/ultralytics/yolo/data/datasets/coco8.yaml b/ultralytics/yolo/data/datasets/coco8.yaml new file mode 100644 index 0000000..7f0ae09 --- /dev/null +++ b/ultralytics/yolo/data/datasets/coco8.yaml @@ -0,0 +1,101 @@ +# Ultralytics YOLO 🚀, GPL-3.0 license +# COCO8 dataset (first 8 images from COCO train2017) by Ultralytics +# Example usage: python train.py --data coco8.yaml +# parent +# ├── yolov5 +# └── datasets +# └── coco8 ← downloads here (1 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/coco8 # dataset root dir +train: images/train # train images (relative to 'path') 4 images +val: images/val # val images (relative to 'path') 4 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/coco8.zip \ No newline at end of file diff --git a/ultralytics/yolo/utils/loss.py b/ultralytics/yolo/utils/loss.py index 60dd6b2..0c6e3c0 100644 --- a/ultralytics/yolo/utils/loss.py +++ b/ultralytics/yolo/utils/loss.py @@ -47,6 +47,7 @@ class BboxLoss(nn.Module): @staticmethod def _df_loss(pred_dist, target): # Return sum of left and right DFL losses + # Distribution Focal Loss (DFL) proposed in Generalized Focal Loss https://ieeexplore.ieee.org/document/9792391 tl = target.long() # target left tr = tl + 1 # target right wl = tr - target # weight left diff --git a/ultralytics/yolo/v8/__init__.py b/ultralytics/yolo/v8/__init__.py index 17700b3..c6ef3d0 100644 --- a/ultralytics/yolo/v8/__init__.py +++ b/ultralytics/yolo/v8/__init__.py @@ -1,11 +1,6 @@ # Ultralytics YOLO 🚀, GPL-3.0 license -from pathlib import Path - +from ultralytics.yolo.configs import hydra_patch # noqa (patch hydra cli) from ultralytics.yolo.v8 import classify, detect, segment -ROOT = Path(__file__).parents[0] # yolov8 ROOT - __all__ = ["classify", "segment", "detect"] - -from ultralytics.yolo.configs import hydra_patch # noqa (patch hydra cli)