ultralytics 8.2.14 add task + OBB to hub.check_dataset() (#12573)

Signed-off-by: Glenn Jocher <glenn.jocher@ultralytics.com>
Co-authored-by: UltralyticsAssistant <web@ultralytics.com>
Co-authored-by: Glenn Jocher <glenn.jocher@ultralytics.com>
This commit is contained in:
Burhan 2024-05-12 15:27:44 -04:00 committed by GitHub
parent cf24349efb
commit fd748e3c7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 36 additions and 24 deletions

View file

@ -12,7 +12,7 @@ import yaml
from PIL import Image from PIL import Image
from ultralytics import RTDETR, YOLO from ultralytics import RTDETR, YOLO
from ultralytics.cfg import MODELS, TASK2DATA from ultralytics.cfg import MODELS, TASKS, TASK2DATA
from ultralytics.data.build import load_inference_source from ultralytics.data.build import load_inference_source
from ultralytics.utils import ( from ultralytics.utils import (
ASSETS, ASSETS,
@ -98,6 +98,12 @@ def test_predict_img(model_name):
assert len(model(batch, imgsz=32)) == len(batch) # multiple sources in a batch assert len(model(batch, imgsz=32)) == len(batch) # multiple sources in a batch
@pytest.mark.parametrize("model", MODELS)
def test_predict_visualize(model):
"""Test model predict methods with 'visualize=True' arguments."""
YOLO(WEIGHTS_DIR / model)(SOURCE, imgsz=32, visualize=True)
def test_predict_grey_and_4ch(): def test_predict_grey_and_4ch():
"""Test YOLO prediction on SOURCE converted to greyscale and 4-channel images.""" """Test YOLO prediction on SOURCE converted to greyscale and 4-channel images."""
im = Image.open(SOURCE) im = Image.open(SOURCE)
@ -267,7 +273,7 @@ def test_data_utils():
# from ultralytics.utils.files import WorkingDirectory # from ultralytics.utils.files import WorkingDirectory
# with WorkingDirectory(ROOT.parent / 'tests'): # with WorkingDirectory(ROOT.parent / 'tests'):
for task in "detect", "segment", "pose", "classify": for task in TASKS:
file = Path(TASK2DATA[task]).with_suffix(".zip") # i.e. coco8.zip file = Path(TASK2DATA[task]).with_suffix(".zip") # i.e. coco8.zip
download(f"https://github.com/ultralytics/hub/raw/main/example_datasets/{file}", unzip=False, dir=TMP) download(f"https://github.com/ultralytics/hub/raw/main/example_datasets/{file}", unzip=False, dir=TMP)
stats = HUBDatasetStats(TMP / file, task=task) stats = HUBDatasetStats(TMP / file, task=task)

View file

@ -1,6 +1,6 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
__version__ = "8.2.13" __version__ = "8.2.14"
from ultralytics.data.explorer.explorer import Explorer from ultralytics.data.explorer.explorer import Explorer
from ultralytics.models import RTDETR, SAM, YOLO, YOLOWorld from ultralytics.models import RTDETR, SAM, YOLO, YOLOWorld

View file

@ -441,6 +441,7 @@ class HUBDatasetStats:
stats = HUBDatasetStats('path/to/coco8.zip', task='detect') # detect dataset stats = HUBDatasetStats('path/to/coco8.zip', task='detect') # detect dataset
stats = HUBDatasetStats('path/to/coco8-seg.zip', task='segment') # segment dataset stats = HUBDatasetStats('path/to/coco8-seg.zip', task='segment') # segment dataset
stats = HUBDatasetStats('path/to/coco8-pose.zip', task='pose') # pose dataset stats = HUBDatasetStats('path/to/coco8-pose.zip', task='pose') # pose dataset
stats = HUBDatasetStats('path/to/dota8.zip', task='obb') # OBB dataset
stats = HUBDatasetStats('path/to/imagenet10.zip', task='classify') # classification dataset stats = HUBDatasetStats('path/to/imagenet10.zip', task='classify') # classification dataset
stats.get_json(save=True) stats.get_json(save=True)
@ -497,13 +498,13 @@ class HUBDatasetStats:
"""Update labels to integer class and 4 decimal place floats.""" """Update labels to integer class and 4 decimal place floats."""
if self.task == "detect": if self.task == "detect":
coordinates = labels["bboxes"] coordinates = labels["bboxes"]
elif self.task == "segment": elif self.task in {"segment", "obb"}: # Segment and OBB use segments. OBB segments are normalized xyxyxyxy
coordinates = [x.flatten() for x in labels["segments"]] coordinates = [x.flatten() for x in labels["segments"]]
elif self.task == "pose": elif self.task == "pose":
n, nk, nd = labels["keypoints"].shape n, nk, nd = labels["keypoints"].shape
coordinates = np.concatenate((labels["bboxes"], labels["keypoints"].reshape(n, nk * nd)), 1) coordinates = np.concatenate((labels["bboxes"], labels["keypoints"].reshape(n, nk * nd)), 1)
else: else:
raise ValueError("Undefined dataset task.") raise ValueError(f"Undefined dataset task={self.task}.")
zipped = zip(labels["cls"], coordinates) zipped = zip(labels["cls"], coordinates)
return [[int(c[0]), *(round(float(x), 4) for x in points)] for c, points in zipped] return [[int(c[0]), *(round(float(x), 4) for x in points)] for c, points in zipped]

View file

@ -106,22 +106,26 @@ def get_export(model_id="", format="torchscript"):
return r.json() return r.json()
def check_dataset(path="", task="detect"): def check_dataset(path: str, task: str) -> None:
""" """
Function for error-checking HUB dataset Zip file before upload. It checks a dataset for errors before it is uploaded Function for error-checking HUB dataset Zip file before upload. It checks a dataset for errors before it is uploaded
to the HUB. Usage examples are given below. to the HUB. Usage examples are given below.
Args: Args:
path (str, optional): Path to data.zip (with data.yaml inside data.zip). Defaults to ''. path (str): Path to data.zip (with data.yaml inside data.zip).
task (str, optional): Dataset task. Options are 'detect', 'segment', 'pose', 'classify'. Defaults to 'detect'. task (str): Dataset task. Options are 'detect', 'segment', 'pose', 'classify', 'obb'.
Example: Example:
Download *.zip files from https://github.com/ultralytics/hub/tree/main/example_datasets
i.e. https://github.com/ultralytics/hub/raw/main/example_datasets/coco8.zip for coco8.zip.
```python ```python
from ultralytics.hub import check_dataset from ultralytics.hub import check_dataset
check_dataset('path/to/coco8.zip', task='detect') # detect dataset check_dataset('path/to/coco8.zip', task='detect') # detect dataset
check_dataset('path/to/coco8-seg.zip', task='segment') # segment dataset check_dataset('path/to/coco8-seg.zip', task='segment') # segment dataset
check_dataset('path/to/coco8-pose.zip', task='pose') # pose dataset check_dataset('path/to/coco8-pose.zip', task='pose') # pose dataset
check_dataset('path/to/dota8.zip', task='obb') # OBB dataset
check_dataset('path/to/imagenet10.zip', task='classify') # classification dataset
``` ```
""" """
HUBDatasetStats(path=path, task=task).get_json() HUBDatasetStats(path=path, task=task).get_json()

View file

@ -1105,23 +1105,24 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path("runs/detec
n (int, optional): Maximum number of feature maps to plot. Defaults to 32. n (int, optional): Maximum number of feature maps to plot. Defaults to 32.
save_dir (Path, optional): Directory to save results. Defaults to Path('runs/detect/exp'). save_dir (Path, optional): Directory to save results. Defaults to Path('runs/detect/exp').
""" """
for m in ["Detect", "Pose", "Segment"]: for m in {"Detect", "Segment", "Pose", "Classify", "OBB", "RTDETRDecoder"}: # all model heads
if m in module_type: if m in module_type:
return return
_, channels, height, width = x.shape # batch, channels, height, width if isinstance(x, torch.Tensor):
if height > 1 and width > 1: _, channels, height, width = x.shape # batch, channels, height, width
f = save_dir / f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename if height > 1 and width > 1:
f = save_dir / f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename
blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels
n = min(n, channels) # number of plots n = min(n, channels) # number of plots
_, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols _, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols
ax = ax.ravel() ax = ax.ravel()
plt.subplots_adjust(wspace=0.05, hspace=0.05) plt.subplots_adjust(wspace=0.05, hspace=0.05)
for i in range(n): for i in range(n):
ax[i].imshow(blocks[i].squeeze()) # cmap='gray' ax[i].imshow(blocks[i].squeeze()) # cmap='gray'
ax[i].axis("off") ax[i].axis("off")
LOGGER.info(f"Saving {f}... ({n}/{channels})") LOGGER.info(f"Saving {f}... ({n}/{channels})")
plt.savefig(f, dpi=300, bbox_inches="tight") plt.savefig(f, dpi=300, bbox_inches="tight")
plt.close() plt.close()
np.save(str(f.with_suffix(".npy")), x[0].cpu().numpy()) # npy save np.save(str(f.with_suffix(".npy")), x[0].cpu().numpy()) # npy save