`ultralytics 8.0.67` Pose speeds, Comet and ClearML updates (#1871)

Co-authored-by: Ayush Chaurasia <ayush.chaurarsia@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Victor Sonck <victor.sonck@gmail.com>
Co-authored-by: Danny Kim <dh031200@gmail.com>
single_channel
Glenn Jocher 2 years ago committed by GitHub
parent 1cb92d7f42
commit 2725545090
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -183,12 +183,12 @@ See [Pose Docs](https://docs.ultralytics.com/tasks/) for usage examples with the
| Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) | | Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) |
| ---------------------------------------------------------------------------------------------------- | --------------------- | -------------------- | --------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- | | ---------------------------------------------------------------------------------------------------- | --------------------- | -------------------- | --------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- |
| [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | - | - | 3.3 | 9.2 | | [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | 131.8 | 1.18 | 3.3 | 9.2 |
| [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | - | - | 11.6 | 30.2 | | [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | 233.2 | 1.42 | 11.6 | 30.2 |
| [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | - | - | 26.4 | 81.0 | | [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | 456.3 | 2.00 | 26.4 | 81.0 |
| [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | - | - | 44.4 | 168.6 | | [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | 784.5 | 2.59 | 44.4 | 168.6 |
| [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | - | - | 69.4 | 263.2 | | [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | 1607.1 | 3.73 | 69.4 | 263.2 |
| [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | - | - | 99.1 | 1066.4 | | [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | 4088.7 | 10.04 | 99.1 | 1066.4 |
- **mAP<sup>val</sup>** values are for single-model single-scale on [COCO Keypoints val2017](http://cocodataset.org) - **mAP<sup>val</sup>** values are for single-model single-scale on [COCO Keypoints val2017](http://cocodataset.org)
dataset. dataset.
@ -214,7 +214,7 @@ See [Pose Docs](https://docs.ultralytics.com/tasks/) for usage examples with the
<a href="https://cutt.ly/yolov5-readme-clearml"> <a href="https://cutt.ly/yolov5-readme-clearml">
<img src="https://github.com/ultralytics/assets/raw/main/partners/logo-clearml.png" width="10%" /></a> <img src="https://github.com/ultralytics/assets/raw/main/partners/logo-clearml.png" width="10%" /></a>
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" /> <img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" />
<a href="https://bit.ly/yolov5-readme-comet2"> <a href="https://bit.ly/yolov8-readme-comet">
<img src="https://github.com/ultralytics/assets/raw/main/partners/logo-comet.png" width="10%" /></a> <img src="https://github.com/ultralytics/assets/raw/main/partners/logo-comet.png" width="10%" /></a>
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" /> <img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" />
<a href="https://bit.ly/yolov5-neuralmagic"> <a href="https://bit.ly/yolov5-neuralmagic">
@ -222,8 +222,8 @@ See [Pose Docs](https://docs.ultralytics.com/tasks/) for usage examples with the
</div> </div>
| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | | Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW |
| :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | | :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: |
| Label and export your custom datasets directly to YOLOv8 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv8 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv8 models, resume training, and interactively visualize and debug predictions | Run YOLOv8 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | | Label and export your custom datasets directly to YOLOv8 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv8 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov8-readme-comet) lets you save YOLOv8 models, resume training, and interactively visualize and debug predictions | Run YOLOv8 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) |
## <div align="center">Ultralytics HUB</div> ## <div align="center">Ultralytics HUB</div>

@ -169,12 +169,12 @@ See [Pose Docs](https://docs.ultralytics.com/tasks/) for usage examples with the
| Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) | | Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) |
| ---------------------------------------------------------------------------------------------------- | --------------------- | -------------------- | --------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- | | ---------------------------------------------------------------------------------------------------- | --------------------- | -------------------- | --------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- |
| [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | - | - | 3.3 | 9.2 | | [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | 131.8 | 1.18 | 3.3 | 9.2 |
| [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | - | - | 11.6 | 30.2 | | [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | 233.2 | 1.42 | 11.6 | 30.2 |
| [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | - | - | 26.4 | 81.0 | | [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | 456.3 | 2.00 | 26.4 | 81.0 |
| [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | - | - | 44.4 | 168.6 | | [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | 784.5 | 2.59 | 44.4 | 168.6 |
| [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | - | - | 69.4 | 263.2 | | [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | 1607.1 | 3.73 | 69.4 | 263.2 |
| [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | - | - | 99.1 | 1066.4 | | [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | 4088.7 | 10.04 | 99.1 | 1066.4 |
- **mAP<sup>val</sup>** values are for single-model single-scale on [COCO Keypoints val2017](http://cocodataset.org) - **mAP<sup>val</sup>** values are for single-model single-scale on [COCO Keypoints val2017](http://cocodataset.org)
dataset. dataset.
@ -200,7 +200,7 @@ See [Pose Docs](https://docs.ultralytics.com/tasks/) for usage examples with the
<a href="https://cutt.ly/yolov5-readme-clearml"> <a href="https://cutt.ly/yolov5-readme-clearml">
<img src="https://github.com/ultralytics/assets/raw/main/partners/logo-clearml.png" width="10%" /></a> <img src="https://github.com/ultralytics/assets/raw/main/partners/logo-clearml.png" width="10%" /></a>
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" /> <img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" />
<a href="https://bit.ly/yolov5-readme-comet2"> <a href="https://bit.ly/yolov8-readme-comet">
<img src="https://github.com/ultralytics/assets/raw/main/partners/logo-comet.png" width="10%" /></a> <img src="https://github.com/ultralytics/assets/raw/main/partners/logo-comet.png" width="10%" /></a>
<img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" /> <img src="https://github.com/ultralytics/assets/raw/main/social/logo-transparent.png" width="15%" height="0" alt="" />
<a href="https://bit.ly/yolov5-neuralmagic"> <a href="https://bit.ly/yolov5-neuralmagic">
@ -208,8 +208,8 @@ See [Pose Docs](https://docs.ultralytics.com/tasks/) for usage examples with the
</div> </div>
| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | | Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 |
| :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | | :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: |
| 将您的自定义数据集进行标注并直接导出到 YOLOv8 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv8 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv8 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv8 推理的速度最高可提高6倍 | | 将您的自定义数据集进行标注并直接导出到 YOLOv8 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv8 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov8-readme-comet)可让您保存 YOLOv8 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv8 推理的速度最高可提高6倍 |
## <div align="center">Ultralytics HUB</div> ## <div align="center">Ultralytics HUB</div>

@ -25,12 +25,12 @@ Ultralytics [release](https://github.com/ultralytics/assets/releases) on first u
| Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) | | Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) |
|------------------------------------------------------------------------------------------------------|-----------------------|----------------------|-----------------------|--------------------------------|-------------------------------------|--------------------|-------------------| |------------------------------------------------------------------------------------------------------|-----------------------|----------------------|-----------------------|--------------------------------|-------------------------------------|--------------------|-------------------|
| [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | - | - | 3.3 | 9.2 | | [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | 131.8 | 1.18 | 3.3 | 9.2 |
| [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | - | - | 11.6 | 30.2 | | [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | 233.2 | 1.42 | 11.6 | 30.2 |
| [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | - | - | 26.4 | 81.0 | | [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | 456.3 | 2.00 | 26.4 | 81.0 |
| [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | - | - | 44.4 | 168.6 | | [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | 784.5 | 2.59 | 44.4 | 168.6 |
| [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | - | - | 69.4 | 263.2 | | [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | 1607.1 | 3.73 | 69.4 | 263.2 |
| [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | - | - | 99.1 | 1066.4 | | [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | 4088.7 | 10.04 | 99.1 | 1066.4 |
- **mAP<sup>val</sup>** values are for single-model single-scale on [COCO Keypoints val2017](http://cocodataset.org) - **mAP<sup>val</sup>** values are for single-model single-scale on [COCO Keypoints val2017](http://cocodataset.org)
dataset. dataset.
@ -123,7 +123,7 @@ Use a trained YOLOv8n-pose model to run predictions on images.
=== "CLI" === "CLI"
```bash ```bash
yolo pose predict model=yolov8n.pt source='https://ultralytics.com/images/bus.jpg' # predict with official model yolo pose predict model=yolov8n-pose.pt source='https://ultralytics.com/images/bus.jpg' # predict with official model
yolo pose predict model=path/to/best.pt source='https://ultralytics.com/images/bus.jpg' # predict with custom model yolo pose predict model=path/to/best.pt source='https://ultralytics.com/images/bus.jpg' # predict with custom model
``` ```
@ -131,7 +131,7 @@ See full `predict` mode details in the [Predict](https://docs.ultralytics.com/mo
## Export ## Export
Export a YOLOv8n model to a different format like ONNX, CoreML, etc. Export a YOLOv8n Pose model to a different format like ONNX, CoreML, etc.
!!! example "" !!! example ""
@ -141,7 +141,7 @@ Export a YOLOv8n model to a different format like ONNX, CoreML, etc.
from ultralytics import YOLO from ultralytics import YOLO
# Load a model # Load a model
model = YOLO('yolov8n.pt') # load an official model model = YOLO('yolov8n-pose.pt') # load an official model
model = YOLO('path/to/best.pt') # load a custom trained model = YOLO('path/to/best.pt') # load a custom trained
# Export the model # Export the model
@ -150,7 +150,7 @@ Export a YOLOv8n model to a different format like ONNX, CoreML, etc.
=== "CLI" === "CLI"
```bash ```bash
yolo export model=yolov8n.pt format=onnx # export official model yolo export model=yolov8n-pose.pt format=onnx # export official model
yolo export model=path/to/best.pt format=onnx # export custom trained model yolo export model=path/to/best.pt format=onnx # export custom trained model
``` ```

@ -2,7 +2,9 @@
from pathlib import Path from pathlib import Path
from ultralytics import YOLO
from ultralytics.yolo.cfg import get_cfg from ultralytics.yolo.cfg import get_cfg
from ultralytics.yolo.engine.exporter import Exporter
from ultralytics.yolo.utils import DEFAULT_CFG, ROOT, SETTINGS from ultralytics.yolo.utils import DEFAULT_CFG, ROOT, SETTINGS
from ultralytics.yolo.v8 import classify, detect, segment from ultralytics.yolo.v8 import classify, detect, segment
@ -14,20 +16,38 @@ MODEL = Path(SETTINGS['weights_dir']) / 'yolov8n'
SOURCE = ROOT / 'assets' SOURCE = ROOT / 'assets'
def test_func(model=None):
print('callback test passed')
def test_export():
exporter = Exporter()
exporter.add_callback('on_export_start', test_func)
assert test_func in exporter.callbacks['on_export_start'], 'callback test failed'
f = exporter(model=YOLO(CFG_DET).model)
YOLO(f)(SOURCE) # exported model inference
def test_detect(): def test_detect():
overrides = {'data': 'coco8.yaml', 'model': CFG_DET, 'imgsz': 32, 'epochs': 1, 'save': False} overrides = {'data': 'coco8.yaml', 'model': CFG_DET, 'imgsz': 32, 'epochs': 1, 'save': False}
CFG.data = 'coco8.yaml' CFG.data = 'coco8.yaml'
# Trainer # Trainer
trainer = detect.DetectionTrainer(overrides=overrides) trainer = detect.DetectionTrainer(overrides=overrides)
trainer.add_callback('on_train_start', test_func)
assert test_func in trainer.callbacks['on_train_start'], 'callback test failed'
trainer.train() trainer.train()
# Validator # Validator
val = detect.DetectionValidator(args=CFG) val = detect.DetectionValidator(args=CFG)
val.add_callback('on_val_start', test_func)
assert test_func in val.callbacks['on_val_start'], 'callback test failed'
val(model=trainer.best) # validate best.pt val(model=trainer.best) # validate best.pt
# Predictor # Predictor
pred = detect.DetectionPredictor(overrides={'imgsz': [64, 64]}) pred = detect.DetectionPredictor(overrides={'imgsz': [64, 64]})
pred.add_callback('on_predict_start', test_func)
assert test_func in pred.callbacks['on_predict_start'], 'callback test failed'
result = pred(source=SOURCE, model=f'{MODEL}.pt') result = pred(source=SOURCE, model=f'{MODEL}.pt')
assert len(result), 'predictor test failed' assert len(result), 'predictor test failed'
@ -50,14 +70,20 @@ def test_segment():
# trainer # trainer
trainer = segment.SegmentationTrainer(overrides=overrides) trainer = segment.SegmentationTrainer(overrides=overrides)
trainer.add_callback('on_train_start', test_func)
assert test_func in trainer.callbacks['on_train_start'], 'callback test failed'
trainer.train() trainer.train()
# Validator # Validator
val = segment.SegmentationValidator(args=CFG) val = segment.SegmentationValidator(args=CFG)
val.add_callback('on_val_start', test_func)
assert test_func in val.callbacks['on_val_start'], 'callback test failed'
val(model=trainer.best) # validate best.pt val(model=trainer.best) # validate best.pt
# Predictor # Predictor
pred = segment.SegmentationPredictor(overrides={'imgsz': [64, 64]}) pred = segment.SegmentationPredictor(overrides={'imgsz': [64, 64]})
pred.add_callback('on_predict_start', test_func)
assert test_func in pred.callbacks['on_predict_start'], 'callback test failed'
result = pred(source=SOURCE, model=f'{MODEL}-seg.pt') result = pred(source=SOURCE, model=f'{MODEL}-seg.pt')
assert len(result), 'predictor test failed' assert len(result), 'predictor test failed'
@ -81,13 +107,19 @@ def test_classify():
# Trainer # Trainer
trainer = classify.ClassificationTrainer(overrides=overrides) trainer = classify.ClassificationTrainer(overrides=overrides)
trainer.add_callback('on_train_start', test_func)
assert test_func in trainer.callbacks['on_train_start'], 'callback test failed'
trainer.train() trainer.train()
# Validator # Validator
val = classify.ClassificationValidator(args=CFG) val = classify.ClassificationValidator(args=CFG)
val.add_callback('on_val_start', test_func)
assert test_func in val.callbacks['on_val_start'], 'callback test failed'
val(model=trainer.best) val(model=trainer.best)
# Predictor # Predictor
pred = classify.ClassificationPredictor(overrides={'imgsz': [64, 64]}) pred = classify.ClassificationPredictor(overrides={'imgsz': [64, 64]})
pred.add_callback('on_predict_start', test_func)
assert test_func in pred.callbacks['on_predict_start'], 'callback test failed'
result = pred(source=SOURCE, model=trainer.best) result = pred(source=SOURCE, model=trainer.best)
assert len(result), 'predictor test failed' assert len(result), 'predictor test failed'

@ -1,6 +1,6 @@
# Ultralytics YOLO 🚀, GPL-3.0 license # Ultralytics YOLO 🚀, GPL-3.0 license
__version__ = '8.0.66' __version__ = '8.0.67'
from ultralytics.hub import start from ultralytics.hub import start
from ultralytics.yolo.engine.model import YOLO from ultralytics.yolo.engine.model import YOLO

@ -3,7 +3,7 @@
import requests import requests
from ultralytics.hub.utils import PREFIX, split_key from ultralytics.hub.utils import PREFIX, split_key
from ultralytics.yolo.utils import LOGGER from ultralytics.yolo.utils import LOGGER, SETTINGS, USER_CONFIG_DIR, yaml_save
def login(api_key=''): def login(api_key=''):
@ -15,7 +15,7 @@ def login(api_key=''):
Example: Example:
from ultralytics import hub from ultralytics import hub
hub.login('your_api_key') hub.login('API_KEY')
""" """
from ultralytics.hub.auth import Auth from ultralytics.hub.auth import Auth
Auth(api_key) Auth(api_key)
@ -23,13 +23,15 @@ def login(api_key=''):
def logout(): def logout():
""" """
Logout Ultralytics HUB Log out of Ultralytics HUB by removing the API key from the settings file. To log in again, use 'yolo hub login'.
Example: Example:
from ultralytics import hub from ultralytics import hub
hub.logout() hub.logout()
""" """
LOGGER.warning('WARNING ⚠️ This method is not yet implemented.') SETTINGS['api_key'] = ''
yaml_save(USER_CONFIG_DIR / 'settings.yaml', SETTINGS)
LOGGER.info(f"{PREFIX}logged out ✅. To log in again, use 'yolo hub login'.")
def start(key=''): def start(key=''):

@ -89,12 +89,12 @@ Available Models:
| Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) | | Model | size<br><sup>(pixels) | mAP<sup>box<br>50-95 | mAP<sup>pose<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) |
| ---------------------------------------------------------------------------------------------------- | --------------------- | -------------------- | --------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- | | ---------------------------------------------------------------------------------------------------- | --------------------- | -------------------- | --------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- |
| [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | - | - | 3.3 | 9.2 | | [YOLOv8n-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n-pose.pt) | 640 | - | 49.7 | 131.8 | 1.18 | 3.3 | 9.2 |
| [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | - | - | 11.6 | 30.2 | | [YOLOv8s-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8s-pose.pt) | 640 | - | 59.2 | 233.2 | 1.42 | 11.6 | 30.2 |
| [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | - | - | 26.4 | 81.0 | | [YOLOv8m-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8m-pose.pt) | 640 | - | 63.6 | 456.3 | 2.00 | 26.4 | 81.0 |
| [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | - | - | 44.4 | 168.6 | | [YOLOv8l-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l-pose.pt) | 640 | - | 67.0 | 784.5 | 2.59 | 44.4 | 168.6 |
| [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | - | - | 69.4 | 263.2 | | [YOLOv8x-pose](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose.pt) | 640 | - | 68.9 | 1607.1 | 3.73 | 69.4 | 263.2 |
| [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | - | - | 99.1 | 1066.4 | | [YOLOv8x-pose-p6](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8x-pose-p6.pt) | 1280 | - | 71.5 | 4088.7 | 10.04 | 99.1 | 1066.4 |
</details> </details>

@ -17,7 +17,7 @@ from PIL import ExifTags, Image, ImageOps
from tqdm import tqdm from tqdm import tqdm
from ultralytics.nn.autobackend import check_class_names from ultralytics.nn.autobackend import check_class_names
from ultralytics.yolo.utils import DATASETS_DIR, LOGGER, NUM_THREADS, ROOT, colorstr, emojis, yaml_load from ultralytics.yolo.utils import DATASETS_DIR, LOGGER, NUM_THREADS, ROOT, clean_url, colorstr, emojis, yaml_load
from ultralytics.yolo.utils.checks import check_file, check_font, is_ascii from ultralytics.yolo.utils.checks import check_file, check_font, is_ascii
from ultralytics.yolo.utils.downloads import download, safe_download, unzip_file from ultralytics.yolo.utils.downloads import download, safe_download, unzip_file
from ultralytics.yolo.utils.ops import segments2boxes from ultralytics.yolo.utils.ops import segments2boxes
@ -241,7 +241,7 @@ def check_det_dataset(dataset, autodownload=True):
if val: if val:
val = [Path(x).resolve() for x in (val if isinstance(val, list) else [val])] # val path 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): if not all(x.exists() for x in val):
name = str(dataset).split('?')[0] # dataset name with URL auth stripped name = clean_url(dataset) # dataset name with URL auth stripped
m = f"\nDataset '{name}' images not found ⚠️, missing paths %s" % [str(x) for x in val if not x.exists()] m = f"\nDataset '{name}' images not found ⚠️, missing paths %s" % [str(x) for x in val if not x.exists()]
if s and autodownload: if s and autodownload:
LOGGER.warning(m) LOGGER.warning(m)

@ -53,7 +53,6 @@ import platform
import subprocess import subprocess
import time import time
import warnings import warnings
from collections import defaultdict
from copy import deepcopy from copy import deepcopy
from pathlib import Path from pathlib import Path
@ -130,7 +129,7 @@ class Exporter:
save_dir (Path): Directory to save results. save_dir (Path): Directory to save results.
""" """
def __init__(self, cfg=DEFAULT_CFG, overrides=None): def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
""" """
Initializes the Exporter class. Initializes the Exporter class.
@ -139,7 +138,7 @@ class Exporter:
overrides (dict, optional): Configuration overrides. Defaults to None. overrides (dict, optional): Configuration overrides. Defaults to None.
""" """
self.args = get_cfg(cfg, overrides) self.args = get_cfg(cfg, overrides)
self.callbacks = defaultdict(list, callbacks.default_callbacks) # add callbacks self.callbacks = _callbacks if _callbacks else callbacks.get_default_callbacks()
callbacks.add_integration_callbacks(self) callbacks.add_integration_callbacks(self)
@smart_inference_mode() @smart_inference_mode()
@ -854,6 +853,12 @@ class Exporter:
LOGGER.info(f'{prefix} pipeline success') LOGGER.info(f'{prefix} pipeline success')
return model return model
def add_callback(self, event: str, callback):
"""
Appends the given callback.
"""
self.callbacks[event].append(callback)
def run_callbacks(self, event: str): def run_callbacks(self, event: str):
for callback in self.callbacks.get(event, []): for callback in self.callbacks.get(event, []):
callback(self) callback(self)

@ -78,7 +78,7 @@ class YOLO:
task (Any, optional): Task type for the YOLO model. Defaults to None. task (Any, optional): Task type for the YOLO model. Defaults to None.
""" """
self._reset_callbacks() self.callbacks = callbacks.get_default_callbacks()
self.predictor = None # reuse predictor self.predictor = None # reuse predictor
self.model = None # model object self.model = None # model object
self.trainer = None # trainer object self.trainer = None # trainer object
@ -238,7 +238,7 @@ class YOLO:
overrides['save'] = kwargs.get('save', False) # not save files by default overrides['save'] = kwargs.get('save', False) # not save files by default
if not self.predictor: if not self.predictor:
self.task = overrides.get('task') or self.task self.task = overrides.get('task') or self.task
self.predictor = TASK_MAP[self.task][3](overrides=overrides) self.predictor = TASK_MAP[self.task][3](overrides=overrides, _callbacks=self.callbacks)
self.predictor.setup_model(model=self.model, verbose=is_cli) self.predictor.setup_model(model=self.model, verbose=is_cli)
else: # only update args if predictor is already setup else: # only update args if predictor is already setup
self.predictor.args = get_cfg(self.predictor.args, overrides) self.predictor.args = get_cfg(self.predictor.args, overrides)
@ -277,7 +277,7 @@ class YOLO:
args.imgsz = self.model.args['imgsz'] # use trained imgsz unless custom value is passed args.imgsz = self.model.args['imgsz'] # use trained imgsz unless custom value is passed
args.imgsz = check_imgsz(args.imgsz, max_dim=1) args.imgsz = check_imgsz(args.imgsz, max_dim=1)
validator = TASK_MAP[self.task][2](args=args) validator = TASK_MAP[self.task][2](args=args, _callbacks=self.callbacks)
validator(model=self.model) validator(model=self.model)
self.metrics = validator.metrics self.metrics = validator.metrics
@ -316,7 +316,7 @@ class YOLO:
args.imgsz = self.model.args['imgsz'] # use trained imgsz unless custom value is passed args.imgsz = self.model.args['imgsz'] # use trained imgsz unless custom value is passed
if args.batch == DEFAULT_CFG.batch: if args.batch == DEFAULT_CFG.batch:
args.batch = 1 # default to 1 if not modified args.batch = 1 # default to 1 if not modified
return Exporter(overrides=args)(model=self.model) return Exporter(overrides=args, _callbacks=self.callbacks)(model=self.model)
def train(self, **kwargs): def train(self, **kwargs):
""" """
@ -344,7 +344,7 @@ class YOLO:
overrides['resume'] = self.ckpt_path overrides['resume'] = self.ckpt_path
self.task = overrides.get('task') or self.task self.task = overrides.get('task') or self.task
self.trainer = TASK_MAP[self.task][1](overrides=overrides) self.trainer = TASK_MAP[self.task][1](overrides=overrides, _callbacks=self.callbacks)
if not overrides.get('resume'): # manually set model only if not resuming if not overrides.get('resume'): # manually set model only if not resuming
self.trainer.model = self.trainer.get_model(weights=self.model if self.ckpt else None, cfg=self.model.yaml) self.trainer.model = self.trainer.get_model(weights=self.model if self.ckpt else None, cfg=self.model.yaml)
self.model = self.trainer.model self.model = self.trainer.model
@ -387,19 +387,17 @@ class YOLO:
""" """
return self.model.transforms if hasattr(self.model, 'transforms') else None return self.model.transforms if hasattr(self.model, 'transforms') else None
@staticmethod def add_callback(self, event: str, func):
def add_callback(event: str, func):
""" """
Add callback Add callback
""" """
callbacks.default_callbacks[event].append(func) self.callbacks[event].append(func)
@staticmethod @staticmethod
def _reset_ckpt_args(args): def _reset_ckpt_args(args):
include = {'imgsz', 'data', 'task', 'single_cls'} # only remember these arguments when loading a PyTorch model include = {'imgsz', 'data', 'task', 'single_cls'} # only remember these arguments when loading a PyTorch model
return {k: v for k, v in args.items() if k in include} return {k: v for k, v in args.items() if k in include}
@staticmethod def _reset_callbacks(self):
def _reset_callbacks():
for event in callbacks.default_callbacks.keys(): for event in callbacks.default_callbacks.keys():
callbacks.default_callbacks[event] = [callbacks.default_callbacks[event][0]] self.callbacks[event] = [callbacks.default_callbacks[event][0]]

@ -28,7 +28,6 @@ Usage - formats:
yolov8n_paddle_model # PaddlePaddle yolov8n_paddle_model # PaddlePaddle
""" """
import platform import platform
from collections import defaultdict
from pathlib import Path from pathlib import Path
import cv2 import cv2
@ -75,7 +74,7 @@ class BasePredictor:
data_path (str): Path to data. data_path (str): Path to data.
""" """
def __init__(self, cfg=DEFAULT_CFG, overrides=None): def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
""" """
Initializes the BasePredictor class. Initializes the BasePredictor class.
@ -104,7 +103,7 @@ class BasePredictor:
self.data_path = None self.data_path = None
self.source_type = None self.source_type = None
self.batch = None self.batch = None
self.callbacks = defaultdict(list, callbacks.default_callbacks) # add callbacks self.callbacks = _callbacks if _callbacks else callbacks.get_default_callbacks()
callbacks.add_integration_callbacks(self) callbacks.add_integration_callbacks(self)
def preprocess(self, img): def preprocess(self, img):
@ -283,3 +282,9 @@ class BasePredictor:
def run_callbacks(self, event: str): def run_callbacks(self, event: str):
for callback in self.callbacks.get(event, []): for callback in self.callbacks.get(event, []):
callback(self) callback(self)
def add_callback(self, event: str, func):
"""
Add callback
"""
self.callbacks[event].append(func)

@ -8,7 +8,6 @@ Usage:
import os import os
import subprocess import subprocess
import time import time
from collections import defaultdict
from copy import deepcopy from copy import deepcopy
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@ -26,7 +25,7 @@ from ultralytics.nn.tasks import attempt_load_one_weight, attempt_load_weights
from ultralytics.yolo.cfg import get_cfg from ultralytics.yolo.cfg import get_cfg
from ultralytics.yolo.data.utils import check_cls_dataset, check_det_dataset from ultralytics.yolo.data.utils import check_cls_dataset, check_det_dataset
from ultralytics.yolo.utils import (DEFAULT_CFG, LOGGER, ONLINE, RANK, ROOT, SETTINGS, TQDM_BAR_FORMAT, __version__, from ultralytics.yolo.utils import (DEFAULT_CFG, LOGGER, ONLINE, RANK, ROOT, SETTINGS, TQDM_BAR_FORMAT, __version__,
callbacks, colorstr, emojis, yaml_save) callbacks, clean_url, colorstr, emojis, yaml_save)
from ultralytics.yolo.utils.autobatch import check_train_batch_size from ultralytics.yolo.utils.autobatch import check_train_batch_size
from ultralytics.yolo.utils.checks import check_file, check_imgsz, print_args from ultralytics.yolo.utils.checks import check_file, check_imgsz, print_args
from ultralytics.yolo.utils.dist import ddp_cleanup, generate_ddp_command from ultralytics.yolo.utils.dist import ddp_cleanup, generate_ddp_command
@ -72,7 +71,7 @@ class BaseTrainer:
csv (Path): Path to results CSV file. csv (Path): Path to results CSV file.
""" """
def __init__(self, cfg=DEFAULT_CFG, overrides=None): def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
""" """
Initializes the BaseTrainer class. Initializes the BaseTrainer class.
@ -124,7 +123,7 @@ class BaseTrainer:
if 'yaml_file' in self.data: if 'yaml_file' in self.data:
self.args.data = self.data['yaml_file'] # for validating 'yolo train data=url.zip' usage self.args.data = self.data['yaml_file'] # for validating 'yolo train data=url.zip' usage
except Exception as e: except Exception as e:
raise RuntimeError(emojis(f"Dataset '{self.args.data}' error ❌ {e}")) from e raise RuntimeError(emojis(f"Dataset '{clean_url(self.args.data)}' error ❌ {e}")) from e
self.trainset, self.testset = self.get_dataset(self.data) self.trainset, self.testset = self.get_dataset(self.data)
self.ema = None self.ema = None
@ -143,7 +142,7 @@ class BaseTrainer:
self.plot_idx = [0, 1, 2] self.plot_idx = [0, 1, 2]
# Callbacks # Callbacks
self.callbacks = defaultdict(list, callbacks.default_callbacks) # add callbacks self.callbacks = _callbacks if _callbacks else callbacks.get_default_callbacks()
if RANK in (-1, 0): if RANK in (-1, 0):
callbacks.add_integration_callbacks(self) callbacks.add_integration_callbacks(self)

@ -19,7 +19,6 @@ Usage - formats:
yolov8n_paddle_model # PaddlePaddle yolov8n_paddle_model # PaddlePaddle
""" """
import json import json
from collections import defaultdict
from pathlib import Path from pathlib import Path
import torch import torch
@ -55,7 +54,7 @@ class BaseValidator:
save_dir (Path): Directory to save results. save_dir (Path): Directory to save results.
""" """
def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None): def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None, _callbacks=None):
""" """
Initializes a BaseValidator instance. Initializes a BaseValidator instance.
@ -85,7 +84,7 @@ class BaseValidator:
if self.args.conf is None: if self.args.conf is None:
self.args.conf = 0.001 # default conf=0.001 self.args.conf = 0.001 # default conf=0.001
self.callbacks = defaultdict(list, callbacks.default_callbacks) # add callbacks self.callbacks = _callbacks if _callbacks else callbacks.get_default_callbacks()
@smart_inference_mode() @smart_inference_mode()
def __call__(self, trainer=None, model=None): def __call__(self, trainer=None, model=None):
@ -195,6 +194,12 @@ class BaseValidator:
LOGGER.info(f"Results saved to {colorstr('bold', self.save_dir)}") LOGGER.info(f"Results saved to {colorstr('bold', self.save_dir)}")
return stats return stats
def add_callback(self, event: str, callback):
"""
Appends the given callback.
"""
self.callbacks[event].append(callback)
def run_callbacks(self, event: str): def run_callbacks(self, event: str):
for callback in self.callbacks.get(event, []): for callback in self.callbacks.get(event, []):
callback(self) callback(self)

@ -10,6 +10,7 @@ import subprocess
import sys import sys
import tempfile import tempfile
import threading import threading
import urllib
import uuid import uuid
from pathlib import Path from pathlib import Path
from types import SimpleNamespace from types import SimpleNamespace
@ -165,7 +166,7 @@ class IterableSimpleNamespace(SimpleNamespace):
def set_logging(name=LOGGING_NAME, verbose=True): def set_logging(name=LOGGING_NAME, verbose=True):
# sets up logging for the given name # 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 level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR
logging.config.dictConfig({ logging.config.dictConfig({
'version': 1, 'version': 1,
'disable_existing_loggers': False, 'disable_existing_loggers': False,
@ -649,10 +650,20 @@ def set_settings(kwargs, file=USER_CONFIG_DIR / 'settings.yaml'):
def deprecation_warn(arg, new_arg, version=None): def deprecation_warn(arg, new_arg, version=None):
if not version: if not version:
version = float(__version__[0:3]) + 0.2 # deprecate after 2nd major release version = float(__version__[:3]) + 0.2 # deprecate after 2nd major release
LOGGER.warning( LOGGER.warning(f"WARNING ⚠️ '{arg}' is deprecated and will be removed in 'ultralytics {version}' in the future. "
f'WARNING: `{arg}` is deprecated and will be removed in upcoming major release {version}. Use `{new_arg}` instead' f"Please use '{new_arg}' instead.")
)
def clean_url(url):
# Strip auth from URL, i.e. https://url.com/file.txt?auth -> https://url.com/file.txt
url = str(Path(url)).replace(':/', '://') # Pathlib turns :// -> :/
return urllib.parse.unquote(url).split('?')[0] # '%2F' to '/', split https://url.com/file.txt?auth
def url2file(url):
# Convert URL to filename, i.e. https://url.com/file.txt?auth -> file.txt
return Path(clean_url(url)).name
# Run below code on yolo/utils init ------------------------------------------------------------------------------------ # Run below code on yolo/utils init ------------------------------------------------------------------------------------

@ -1,3 +1,3 @@
from .base import add_integration_callbacks, default_callbacks from .base import add_integration_callbacks, default_callbacks, get_default_callbacks
__all__ = 'add_integration_callbacks', 'default_callbacks' __all__ = 'add_integration_callbacks', 'default_callbacks', 'get_default_callbacks'

@ -2,6 +2,8 @@
""" """
Base callbacks Base callbacks
""" """
from collections import defaultdict
from copy import deepcopy
# Trainer callbacks ---------------------------------------------------------------------------------------------------- # Trainer callbacks ----------------------------------------------------------------------------------------------------
@ -143,6 +145,10 @@ default_callbacks = {
'on_export_end': [on_export_end]} 'on_export_end': [on_export_end]}
def get_default_callbacks():
return defaultdict(list, deepcopy(default_callbacks))
def add_integration_callbacks(instance): def add_integration_callbacks(instance):
from .clearml import callbacks as clearml_callbacks from .clearml import callbacks as clearml_callbacks
from .comet import callbacks as comet_callbacks from .comet import callbacks as comet_callbacks

@ -1,10 +1,17 @@
# Ultralytics YOLO 🚀, GPL-3.0 license # Ultralytics YOLO 🚀, GPL-3.0 license
import re
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from ultralytics.yolo.utils import LOGGER, TESTS_RUNNING from ultralytics.yolo.utils import LOGGER, TESTS_RUNNING
from ultralytics.yolo.utils.torch_utils import get_flops, get_num_params from ultralytics.yolo.utils.torch_utils import get_flops, get_num_params
try: try:
import clearml import clearml
from clearml import Task from clearml import Task
from clearml.binding.frameworks.pytorch_bind import PatchPyTorchModelIO
from clearml.binding.matplotlib_bind import PatchedMatplotlib
assert hasattr(clearml, '__version__') # verify package is not directory assert hasattr(clearml, '__version__') # verify package is not directory
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
@ -12,21 +19,61 @@ except (ImportError, AssertionError):
clearml = None clearml = None
def _log_images(imgs_dict, group='', step=0): def _log_debug_samples(files, title='Debug Samples'):
task = Task.current_task() """
if task: Log files (images) as debug samples in the ClearML task.
for k, v in imgs_dict.items():
task.get_logger().report_image(group, k, step, v) 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
Task.current_task().get_logger().report_image(title=title,
series=f.name.replace(it.group(), ''),
local_path=str(f),
iteration=iteration)
def _log_plot(title, plot_path):
"""
Log image as plot in the plot section of ClearML
arguments:
title (str) Title of the plot
plot_path (PosixPath or str) Path to the saved image file
"""
img = mpimg.imread(plot_path)
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], frameon=False, aspect='auto', xticks=[], yticks=[]) # no ticks
ax.imshow(img)
Task.current_task().get_logger().report_matplotlib_figure(title, '', figure=fig, report_interactive=False)
def on_pretrain_routine_start(trainer): def on_pretrain_routine_start(trainer):
# TODO: reuse existing task
try: try:
if Task.current_task():
task = Task.current_task()
# Make sure the automatic pytorch and matplotlib bindings are disabled!
# We are logging these plots and model files manually in the integration
PatchPyTorchModelIO.update_current_task(None)
PatchedMatplotlib.update_current_task(None)
else:
task = Task.init(project_name=trainer.args.project or 'YOLOv8', task = Task.init(project_name=trainer.args.project or 'YOLOv8',
task_name=trainer.args.name, task_name=trainer.args.name,
tags=['YOLOv8'], tags=['YOLOv8'],
output_uri=True, output_uri=True,
reuse_last_task_id=False, reuse_last_task_id=False,
auto_connect_frameworks={'pytorch': False}) auto_connect_frameworks={
'pytorch': False,
'matplotlib': False})
LOGGER.warning('ClearML Initialized a new task. If you want to run remotely, '
'please add clearml-init and connect your arguments before initializing YOLO.')
task.connect(vars(trainer.args), name='General') task.connect(vars(trainer.args), name='General')
except Exception as e: except Exception as e:
LOGGER.warning(f'WARNING ⚠️ ClearML installed but not initialized correctly, not logging this run. {e}') LOGGER.warning(f'WARNING ⚠️ ClearML installed but not initialized correctly, not logging this run. {e}')
@ -34,27 +81,47 @@ def on_pretrain_routine_start(trainer):
def on_train_epoch_end(trainer): def on_train_epoch_end(trainer):
if trainer.epoch == 1: if trainer.epoch == 1:
_log_images({f.stem: str(f) for f in trainer.save_dir.glob('train_batch*.jpg')}, 'Mosaic', trainer.epoch) _log_debug_samples(sorted(trainer.save_dir.glob('train_batch*.jpg')), 'Mosaic')
def on_fit_epoch_end(trainer): def on_fit_epoch_end(trainer):
task = Task.current_task() # You should have access to the validation bboxes under jdict
if task and trainer.epoch == 0: Task.current_task().get_logger().report_scalar(title='Epoch Time',
series='Epoch Time',
value=trainer.epoch_time,
iteration=trainer.epoch)
if trainer.epoch == 0:
model_info = { model_info = {
'model/parameters': get_num_params(trainer.model), 'model/parameters': get_num_params(trainer.model),
'model/GFLOPs': round(get_flops(trainer.model), 3), 'model/GFLOPs': round(get_flops(trainer.model), 3),
'model/speed(ms)': round(trainer.validator.speed['inference'], 3)} 'model/speed(ms)': round(trainer.validator.speed['inference'], 3)}
task.connect(model_info, name='Model') for k, v in model_info.items():
Task.current_task().get_logger().report_single_value(k, v)
def on_val_end(validator):
# Log val_labels and val_pred
_log_debug_samples(sorted(validator.save_dir.glob('val*.jpg')), 'Validation')
def on_train_end(trainer): def on_train_end(trainer):
task = Task.current_task() # Log final results, CM matrix + PR plots
if task: files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))]
task.update_output_model(model_path=str(trainer.best), model_name=trainer.args.name, auto_delete_file=False) files = [(trainer.save_dir / f) for f in files if (trainer.save_dir / f).exists()] # filter
for f in files:
_log_plot(title=f.stem, plot_path=f)
# Report final metrics
for k, v in trainer.validator.metrics.results_dict.items():
Task.current_task().get_logger().report_single_value(k, v)
# Log the final model
Task.current_task().update_output_model(model_path=str(trainer.best),
model_name=trainer.args.name,
auto_delete_file=False)
callbacks = { callbacks = {
'on_pretrain_routine_start': on_pretrain_routine_start, 'on_pretrain_routine_start': on_pretrain_routine_start,
'on_train_epoch_end': on_train_epoch_end, 'on_train_epoch_end': on_train_epoch_end,
'on_fit_epoch_end': on_fit_epoch_end, 'on_fit_epoch_end': on_fit_epoch_end,
'on_val_end': on_val_end,
'on_train_end': on_train_end} if clearml else {} 'on_train_end': on_train_end} if clearml else {}

@ -1,5 +1,8 @@
# Ultralytics YOLO 🚀, GPL-3.0 license # Ultralytics YOLO 🚀, GPL-3.0 license
from ultralytics.yolo.utils import LOGGER, TESTS_RUNNING import os
from pathlib import Path
from ultralytics.yolo.utils import LOGGER, RANK, TESTS_RUNNING, ops
from ultralytics.yolo.utils.torch_utils import get_flops, get_num_params from ultralytics.yolo.utils.torch_utils import get_flops, get_num_params
try: try:
@ -10,41 +13,308 @@ try:
except (ImportError, AssertionError): except (ImportError, AssertionError):
comet_ml = None comet_ml = None
COMET_MODE = os.getenv('COMET_MODE', 'online')
COMET_MODEL_NAME = os.getenv('COMET_MODEL_NAME', 'YOLOv8')
# determines how many batches of image predictions to log from the validation set
COMET_EVAL_BATCH_LOGGING_INTERVAL = int(os.getenv('COMET_EVAL_BATCH_LOGGING_INTERVAL', 1))
# determines whether to log confusion matrix every evaluation epoch
COMET_EVAL_LOG_CONFUSION_MATRIX = (os.getenv('COMET_EVAL_LOG_CONFUSION_MATRIX', 'true').lower() == 'true')
# determines whether to log image predictions every evaluation epoch
COMET_EVAL_LOG_IMAGE_PREDICTIONS = (os.getenv('COMET_EVAL_LOG_IMAGE_PREDICTIONS', 'true').lower() == 'true')
COMET_MAX_IMAGE_PREDICTIONS = int(os.getenv('COMET_MAX_IMAGE_PREDICTIONS', 100))
def on_pretrain_routine_start(trainer): # ensures certain logging functions only run for supported tasks
COMET_SUPPORTED_TASKS = ['detect']
# scales reported confidence scores (0.0-1.0) by this value
COMET_MAX_CONFIDENCE_SCORE = int(os.getenv('COMET_MAX_CONFIDENCE_SCORE', 100))
# names of plots created by YOLOv8 that are logged to Comet
EVALUATION_PLOT_NAMES = 'F1_curve', 'P_curve', 'R_curve', 'PR_curve', 'confusion_matrix'
LABEL_PLOT_NAMES = 'labels', 'labels_correlogram'
_comet_image_prediction_count = 0
def _get_experiment_type(mode, project_name):
if mode == 'offline':
return comet_ml.OfflineExperiment(project_name=project_name)
return comet_ml.Experiment(project_name=project_name)
def _create_experiment(args):
# Ensures that the experiment object is only created in a single process during distributed training.
if RANK not in (-1, 0):
return
try: try:
experiment = comet_ml.Experiment(project_name=trainer.args.project or 'YOLOv8') experiment = _get_experiment_type(COMET_MODE, args.project)
experiment.set_name(trainer.args.name) experiment.log_parameters(vars(args))
experiment.log_parameters(vars(trainer.args)) experiment.log_others({
'eval_batch_logging_interval': COMET_EVAL_BATCH_LOGGING_INTERVAL,
'log_confusion_matrix': COMET_EVAL_LOG_CONFUSION_MATRIX,
'log_image_predictions': COMET_EVAL_LOG_IMAGE_PREDICTIONS,
'max_image_predictions': COMET_MAX_IMAGE_PREDICTIONS, })
experiment.log_other('Created from', 'yolov8')
except Exception as e: except Exception as e:
LOGGER.warning(f'WARNING ⚠️ Comet installed but not initialized correctly, not logging this run. {e}') LOGGER.warning(f'WARNING ⚠️ Comet installed but not initialized correctly, not logging this run. {e}')
def _fetch_trainer_metadata(trainer):
curr_epoch = trainer.epoch + 1
train_num_steps_per_epoch = len(trainer.train_loader.dataset) // trainer.batch_size
curr_step = curr_epoch * train_num_steps_per_epoch
final_epoch = curr_epoch == trainer.epochs
save = trainer.args.save
save_period = trainer.args.save_period
save_interval = curr_epoch % save_period == 0
save_assets = save and save_period > 0 and save_interval and not final_epoch
return dict(curr_epoch=curr_epoch, curr_step=curr_step, save_assets=save_assets, final_epoch=final_epoch)
def _scale_bounding_box_to_original_image_shape(box, resized_image_shape, original_image_shape, ratio_pad):
"""YOLOv8 resizes images during training and the label values
are normalized based on this resized shape. This function rescales the
bounding box labels to the original image shape.
"""
resized_image_height, resized_image_width = resized_image_shape
# convert normalized xywh format predictions to xyxy in resized scale format
box = ops.xywhn2xyxy(box, h=resized_image_height, w=resized_image_width)
# scale box predictions from resized image scale back to original image scale
box = ops.scale_boxes(resized_image_shape, box, original_image_shape, ratio_pad)
# Convert bounding box format from xyxy to xywh for Comet logging
box = ops.xyxy2xywh(box)
# adjust xy center to correspond top-left corner
box[:2] -= box[2:] / 2
box = box.tolist()
return box
def _format_ground_truth_annotations_for_detection(img_idx, image_path, batch, class_name_map=None):
indices = batch['batch_idx'] == img_idx
bboxes = batch['bboxes'][indices]
if len(bboxes) == 0:
LOGGER.debug(f'COMET WARNING: Image: {image_path} has no bounding boxes labels')
return None
cls_labels = batch['cls'][indices].squeeze(1).tolist()
if class_name_map:
cls_labels = [str(class_name_map[label]) for label in cls_labels]
original_image_shape = batch['ori_shape'][img_idx]
resized_image_shape = batch['resized_shape'][img_idx]
ratio_pad = batch['ratio_pad'][img_idx]
data = []
for box, label in zip(bboxes, cls_labels):
box = _scale_bounding_box_to_original_image_shape(box, resized_image_shape, original_image_shape, ratio_pad)
data.append({'boxes': [box], 'label': f'gt_{label}', 'score': COMET_MAX_CONFIDENCE_SCORE})
return {'name': 'ground_truth', 'data': data}
def _format_prediction_annotations_for_detection(image_path, metadata, class_label_map=None):
stem = image_path.stem
image_id = int(stem) if stem.isnumeric() else stem
predictions = metadata.get(image_id)
if not predictions:
LOGGER.debug(f'COMET WARNING: Image: {image_path} has no bounding boxes predictions')
return None
data = []
for prediction in predictions:
boxes = prediction['bbox']
score = prediction['score'] * COMET_MAX_CONFIDENCE_SCORE
cls_label = prediction['category_id']
if class_label_map:
cls_label = str(class_label_map[cls_label])
data.append({'boxes': [boxes], 'label': cls_label, 'score': score})
return {'name': 'prediction', 'data': data}
def _fetch_annotations(img_idx, image_path, batch, prediction_metadata_map, class_label_map):
ground_truth_annotations = _format_ground_truth_annotations_for_detection(img_idx, image_path, batch,
class_label_map)
prediction_annotations = _format_prediction_annotations_for_detection(image_path, prediction_metadata_map,
class_label_map)
annotations = [
annotation for annotation in [ground_truth_annotations, prediction_annotations] if annotation is not None]
return [annotations] if annotations else None
def _create_prediction_metadata_map(model_predictions):
pred_metadata_map = {}
for prediction in model_predictions:
pred_metadata_map.setdefault(prediction['image_id'], [])
pred_metadata_map[prediction['image_id']].append(prediction)
return pred_metadata_map
def _log_confusion_matrix(experiment, trainer, curr_step, curr_epoch):
conf_mat = trainer.validator.confusion_matrix.matrix
names = list(trainer.data['names'].values()) + ['background']
experiment.log_confusion_matrix(
matrix=conf_mat,
labels=names,
max_categories=len(names),
epoch=curr_epoch,
step=curr_step,
)
def _log_images(experiment, image_paths, curr_step, annotations=None):
if annotations:
for image_path, annotation in zip(image_paths, annotations):
experiment.log_image(image_path, name=image_path.stem, step=curr_step, annotations=annotation)
else:
for image_path in image_paths:
experiment.log_image(image_path, name=image_path.stem, step=curr_step)
def _log_image_predictions(experiment, validator, curr_step):
global _comet_image_prediction_count
task = validator.args.task
if task not in COMET_SUPPORTED_TASKS:
return
jdict = validator.jdict
if not jdict:
return
predictions_metadata_map = _create_prediction_metadata_map(jdict)
dataloader = validator.dataloader
class_label_map = validator.names
for batch_idx, batch in enumerate(dataloader):
if (batch_idx + 1) % COMET_EVAL_BATCH_LOGGING_INTERVAL != 0:
continue
image_paths = batch['im_file']
for img_idx, image_path in enumerate(image_paths):
if _comet_image_prediction_count >= COMET_MAX_IMAGE_PREDICTIONS:
return
image_path = Path(image_path)
annotations = _fetch_annotations(
img_idx,
image_path,
batch,
predictions_metadata_map,
class_label_map,
)
_log_images(
experiment,
[image_path],
curr_step,
annotations=annotations,
)
_comet_image_prediction_count += 1
def _log_plots(experiment, trainer):
plot_filenames = [trainer.save_dir / f'{plots}.png' for plots in EVALUATION_PLOT_NAMES]
_log_images(experiment, plot_filenames, None)
label_plot_filenames = [trainer.save_dir / f'{labels}.jpg' for labels in LABEL_PLOT_NAMES]
_log_images(experiment, label_plot_filenames, None)
def _log_model(experiment, trainer):
experiment.log_model(
COMET_MODEL_NAME,
file_or_folder=str(trainer.best),
file_name='best.pt',
overwrite=True,
)
def on_pretrain_routine_start(trainer):
experiment = comet_ml.get_global_experiment()
if not experiment:
_create_experiment(trainer.args)
def on_train_epoch_end(trainer): def on_train_epoch_end(trainer):
experiment = comet_ml.get_global_experiment() experiment = comet_ml.get_global_experiment()
if experiment: if not experiment:
experiment.log_metrics(trainer.label_loss_items(trainer.tloss, prefix='train'), step=trainer.epoch + 1) return
if trainer.epoch == 1:
for f in trainer.save_dir.glob('train_batch*.jpg'): metadata = _fetch_trainer_metadata(trainer)
experiment.log_image(f, name=f.stem, step=trainer.epoch + 1) curr_epoch = metadata['curr_epoch']
curr_step = metadata['curr_step']
experiment.log_metrics(
trainer.label_loss_items(trainer.tloss, prefix='train'),
step=curr_step,
epoch=curr_epoch,
)
if curr_epoch == 1:
_log_images(experiment, trainer.save_dir.glob('train_batch*.jpg'), curr_step)
def on_fit_epoch_end(trainer): def on_fit_epoch_end(trainer):
experiment = comet_ml.get_global_experiment() experiment = comet_ml.get_global_experiment()
if experiment: if not experiment:
experiment.log_metrics(trainer.metrics, step=trainer.epoch + 1) return
if trainer.epoch == 0:
metadata = _fetch_trainer_metadata(trainer)
curr_epoch = metadata['curr_epoch']
curr_step = metadata['curr_step']
save_assets = metadata['save_assets']
experiment.log_metrics(trainer.metrics, step=curr_step, epoch=curr_epoch)
experiment.log_metrics(trainer.lr, step=curr_step, epoch=curr_epoch)
if curr_epoch == 1:
model_info = { model_info = {
'model/parameters': get_num_params(trainer.model), 'model/parameters': get_num_params(trainer.model),
'model/GFLOPs': round(get_flops(trainer.model), 3), 'model/GFLOPs': round(get_flops(trainer.model), 3),
'model/speed(ms)': round(trainer.validator.speed['inference'], 3)} 'model/speed(ms)': round(trainer.validator.speed['inference'], 3)}
experiment.log_metrics(model_info, step=trainer.epoch + 1) experiment.log_metrics(model_info, step=curr_step, epoch=curr_epoch)
if not save_assets:
return
_log_model(experiment, trainer)
if COMET_EVAL_LOG_CONFUSION_MATRIX:
_log_confusion_matrix(experiment, trainer, curr_step, curr_epoch)
if COMET_EVAL_LOG_IMAGE_PREDICTIONS:
_log_image_predictions(experiment, trainer.validator, curr_step)
def on_train_end(trainer): def on_train_end(trainer):
experiment = comet_ml.get_global_experiment() experiment = comet_ml.get_global_experiment()
if experiment: if not experiment:
experiment.log_model('YOLOv8', file_or_folder=str(trainer.best), file_name='best.pt', overwrite=True) return
metadata = _fetch_trainer_metadata(trainer)
curr_epoch = metadata['curr_epoch']
curr_step = metadata['curr_step']
plots = trainer.args.plots
_log_model(experiment, trainer)
if plots:
_log_plots(experiment, trainer)
_log_confusion_matrix(experiment, trainer, curr_step, curr_epoch)
_log_image_predictions(experiment, trainer.validator, curr_step)
experiment.end()
global _comet_image_prediction_count
_comet_image_prediction_count = 0
callbacks = { callbacks = {

@ -8,7 +8,6 @@ import platform
import re import re
import shutil import shutil
import subprocess import subprocess
import urllib
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
@ -20,8 +19,9 @@ import requests
import torch import torch
from matplotlib import font_manager from matplotlib import font_manager
from ultralytics.yolo.utils import (AUTOINSTALL, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, TryExcept, colorstr, downloads, from ultralytics.yolo.utils import (AUTOINSTALL, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, TryExcept, clean_url, colorstr,
emojis, is_colab, is_docker, is_kaggle, is_online, is_pip_package) downloads, emojis, is_colab, is_docker, is_kaggle, is_online, is_pip_package,
url2file)
def is_ascii(s) -> bool: def is_ascii(s) -> bool:
@ -267,9 +267,9 @@ def check_file(file, suffix='', download=True, hard=True):
return file return file
elif download and file.lower().startswith(('https://', 'http://', 'rtsp://', 'rtmp://')): # download elif download and file.lower().startswith(('https://', 'http://', 'rtsp://', 'rtmp://')): # download
url = file # warning: 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 file = url2file(file) # '%2F' to '/', split https://url.com/file.txt?auth
if Path(file).exists(): if Path(file).exists():
LOGGER.info(f'Found {url} locally at {file}') # file already exists LOGGER.info(f'Found {clean_url(url)} locally at {file}') # file already exists
else: else:
downloads.safe_download(url=url, file=file, unzip=False) downloads.safe_download(url=url, file=file, unzip=False)
return file return file

@ -12,7 +12,7 @@ import requests
import torch import torch
from tqdm import tqdm from tqdm import tqdm
from ultralytics.yolo.utils import LOGGER, checks, emojis, is_online from ultralytics.yolo.utils import LOGGER, checks, clean_url, emojis, is_online, url2file
GITHUB_ASSET_NAMES = [f'yolov8{k}{suffix}.pt' for k in 'nsmlx' for suffix in ('', '6', '-cls', '-seg', '-pose')] + \ GITHUB_ASSET_NAMES = [f'yolov8{k}{suffix}.pt' for k in 'nsmlx' for suffix in ('', '6', '-cls', '-seg', '-pose')] + \
[f'yolov5{k}u.pt' for k in 'nsmlx'] + \ [f'yolov5{k}u.pt' for k in 'nsmlx'] + \
@ -43,10 +43,18 @@ def unzip_file(file, path=None, exclude=('.DS_Store', '__MACOSX')):
if path is None: if path is None:
path = Path(file).parent # default path path = Path(file).parent # default path
with ZipFile(file) as zipObj: with ZipFile(file) as zipObj:
for f in zipObj.namelist(): # list all archived filenames in the zip for i, f in enumerate(zipObj.namelist()): # list all archived filenames in the zip
# If zip does not expand into a directory create a new directory to expand into
if i == 0:
info = zipObj.getinfo(f)
if info.file_size > 0 or not info.filename.endswith('/'): # element is a file and not a directory
path = Path(path) / Path(file).stem # define new unzip directory
unzip_dir = path
else:
unzip_dir = f
if all(x not in f for x in exclude): if all(x not in f for x in exclude):
zipObj.extract(f, path=path) zipObj.extract(f, path=path)
return zipObj.namelist()[0] # return unzip dir return unzip_dir # return unzip dir
def safe_download(url, def safe_download(url,
@ -79,8 +87,8 @@ def safe_download(url,
f = Path(url) # filename f = Path(url) # filename
else: # does not exist else: # does not exist
assert dir or file, 'dir or file required for download' assert dir or file, 'dir or file required for download'
f = dir / Path(url).name if dir else Path(file) f = dir / url2file(url) if dir else Path(file)
desc = f'Downloading {url} to {f}' desc = f'Downloading {clean_url(url)} to {f}'
LOGGER.info(f'{desc}...') LOGGER.info(f'{desc}...')
f.parent.mkdir(parents=True, exist_ok=True) # make directory if missing f.parent.mkdir(parents=True, exist_ok=True) # make directory if missing
for i in range(retry + 1): for i in range(retry + 1):
@ -156,9 +164,9 @@ def attempt_download_asset(file, repo='ultralytics/assets', release='v0.0.0'):
name = Path(parse.unquote(str(file))).name # decode '%2F' to '/' etc. name = Path(parse.unquote(str(file))).name # decode '%2F' to '/' etc.
if str(file).startswith(('http:/', 'https:/')): # download if str(file).startswith(('http:/', 'https:/')): # download
url = str(file).replace(':/', '://') # Pathlib turns :// -> :/ url = str(file).replace(':/', '://') # Pathlib turns :// -> :/
file = name.split('?')[0] # parse authentication https://url.com/file.txt?auth... file = url2file(name) # parse authentication https://url.com/file.txt?auth...
if Path(file).is_file(): if Path(file).is_file():
LOGGER.info(f'Found {url} locally at {file}') # file already exists LOGGER.info(f'Found {clean_url(url)} locally at {file}') # file already exists
else: else:
safe_download(url=url, file=file, min_bytes=1E5) safe_download(url=url, file=file, min_bytes=1E5)
return file return file

@ -3,7 +3,6 @@
import contextlib import contextlib
import glob import glob
import os import os
import urllib
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@ -80,12 +79,6 @@ def file_size(path):
return 0.0 return 0.0
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
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) # 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) last_list = glob.glob(f'{search_dir}/**/last*.pt', recursive=True)

@ -13,11 +13,11 @@ from ultralytics.yolo.utils.torch_utils import is_parallel, strip_optimizer
class ClassificationTrainer(BaseTrainer): class ClassificationTrainer(BaseTrainer):
def __init__(self, cfg=DEFAULT_CFG, overrides=None): def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
if overrides is None: if overrides is None:
overrides = {} overrides = {}
overrides['task'] = 'classify' overrides['task'] = 'classify'
super().__init__(cfg, overrides) super().__init__(cfg, overrides, _callbacks)
def set_model_attributes(self): def set_model_attributes(self):
self.model.names = self.data['names'] self.model.names = self.data['names']

@ -8,8 +8,8 @@ from ultralytics.yolo.utils.metrics import ClassifyMetrics
class ClassificationValidator(BaseValidator): class ClassificationValidator(BaseValidator):
def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None): def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None, _callbacks=None):
super().__init__(dataloader, save_dir, pbar, args) super().__init__(dataloader, save_dir, pbar, args, _callbacks)
self.args.task = 'classify' self.args.task = 'classify'
self.metrics = ClassifyMetrics() self.metrics = ClassifyMetrics()

@ -18,8 +18,8 @@ from ultralytics.yolo.utils.torch_utils import de_parallel
class DetectionValidator(BaseValidator): class DetectionValidator(BaseValidator):
def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None): def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None, _callbacks=None):
super().__init__(dataloader, save_dir, pbar, args) super().__init__(dataloader, save_dir, pbar, args, _callbacks)
self.args.task = 'detect' self.args.task = 'detect'
self.is_coco = False self.is_coco = False
self.class_map = None self.class_map = None

@ -20,11 +20,11 @@ from ultralytics.yolo.v8.detect.train import Loss
# BaseTrainer python usage # BaseTrainer python usage
class PoseTrainer(v8.detect.DetectionTrainer): class PoseTrainer(v8.detect.DetectionTrainer):
def __init__(self, cfg=DEFAULT_CFG, overrides=None): def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
if overrides is None: if overrides is None:
overrides = {} overrides = {}
overrides['task'] = 'pose' overrides['task'] = 'pose'
super().__init__(cfg, overrides) super().__init__(cfg, overrides, _callbacks)
def get_model(self, cfg=None, weights=None, verbose=True): def get_model(self, cfg=None, weights=None, verbose=True):
model = PoseModel(cfg, ch=3, nc=self.data['nc'], data_kpt_shape=self.data['kpt_shape'], verbose=verbose) model = PoseModel(cfg, ch=3, nc=self.data['nc'], data_kpt_shape=self.data['kpt_shape'], verbose=verbose)

@ -14,8 +14,8 @@ from ultralytics.yolo.v8.detect import DetectionValidator
class PoseValidator(DetectionValidator): class PoseValidator(DetectionValidator):
def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None): def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None, _callbacks=None):
super().__init__(dataloader, save_dir, pbar, args) super().__init__(dataloader, save_dir, pbar, args, _callbacks)
self.args.task = 'pose' self.args.task = 'pose'
self.metrics = PoseMetrics(save_dir=self.save_dir) self.metrics = PoseMetrics(save_dir=self.save_dir)

@ -17,11 +17,11 @@ from ultralytics.yolo.v8.detect.train import Loss
# BaseTrainer python usage # BaseTrainer python usage
class SegmentationTrainer(v8.detect.DetectionTrainer): class SegmentationTrainer(v8.detect.DetectionTrainer):
def __init__(self, cfg=DEFAULT_CFG, overrides=None): def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
if overrides is None: if overrides is None:
overrides = {} overrides = {}
overrides['task'] = 'segment' overrides['task'] = 'segment'
super().__init__(cfg, overrides) super().__init__(cfg, overrides, _callbacks)
def get_model(self, cfg=None, weights=None, verbose=True): def get_model(self, cfg=None, weights=None, verbose=True):
model = SegmentationModel(cfg, ch=3, nc=self.data['nc'], verbose=verbose and RANK == -1) model = SegmentationModel(cfg, ch=3, nc=self.data['nc'], verbose=verbose and RANK == -1)

@ -16,8 +16,8 @@ from ultralytics.yolo.v8.detect import DetectionValidator
class SegmentationValidator(DetectionValidator): class SegmentationValidator(DetectionValidator):
def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None): def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None, _callbacks=None):
super().__init__(dataloader, save_dir, pbar, args) super().__init__(dataloader, save_dir, pbar, args, _callbacks)
self.args.task = 'segment' self.args.task = 'segment'
self.metrics = SegmentMetrics(save_dir=self.save_dir) self.metrics = SegmentMetrics(save_dir=self.save_dir)

Loading…
Cancel
Save