diff --git a/docs/build_docs.py b/docs/build_docs.py
index 4d7f9393..67ec5bd1 100644
--- a/docs/build_docs.py
+++ b/docs/build_docs.py
@@ -192,7 +192,7 @@ def convert_plaintext_links_to_html(content):
for paragraph in main_content.find_all(["p", "li"]): # Focus on paragraphs and list items
for text_node in paragraph.find_all(string=True, recursive=False):
if text_node.parent.name not in {"a", "code"}: # Ignore links and code blocks
- new_text = re.sub(r"(https?://\S+)", r'\1', str(text_node)) # note: reject http?
+ new_text = re.sub(r"(https?://\S+?)(?=[,.!?;:]?\s|[,.!?;:]?$)", r'\1', str(text_node))
if ">> from ultralytics import get_cfg
+ >>> from ultralytics.cfg import get_cfg
>>> config = get_cfg() # Load default configuration
>>> config = get_cfg('path/to/config.yaml', overrides={'epochs': 50, 'batch_size': 16})
@@ -546,16 +546,19 @@ def handle_yolo_settings(args: List[str]) -> None:
LOGGER.warning(f"WARNING ⚠️ settings error: '{e}'. Please see {url} for help.")
-def handle_explorer():
+def handle_explorer(args: List[str]):
"""
- Open the Ultralytics Explorer GUI for dataset exploration and analysis.
+ This function launches a graphical user interface that provides tools for interacting with and analyzing datasets
+ using the Ultralytics Explorer API. It checks for the required 'streamlit' package and informs the user that the
+ Explorer dashboard is loading.
- This function launches a graphical user interface that provides tools for interacting with and analyzing
- datasets using the Ultralytics Explorer API. It checks for the required 'streamlit' package and informs
- the user that the Explorer dashboard is loading.
+ Args:
+ args (List[str]): A list of optional command line arguments.
Examples:
- >>> handle_explorer()
+ ```bash
+ yolo explorer data=data.yaml model=yolov8n.pt
+ ```
Notes:
- Requires 'streamlit' package version 1.29.0 or higher.
@@ -564,7 +567,12 @@ def handle_explorer():
"""
checks.check_requirements("streamlit>=1.29.0")
LOGGER.info("💡 Loading Explorer dashboard...")
- subprocess.run(["streamlit", "run", ROOT / "data/explorer/gui/dash.py", "--server.maxMessageSize", "2048"])
+ cmd = ["streamlit", "run", ROOT / "data/explorer/gui/dash.py", "--server.maxMessageSize", "2048"]
+ new = dict(parse_key_value_pair(a) for a in args)
+ check_dict_alignment(base={k: DEFAULT_CFG_DICT[k] for k in ["model", "data"]}, custom=new)
+ for k, v in new.items():
+ cmd += [k, v]
+ subprocess.run(cmd)
def handle_streamlit_inference():
@@ -587,7 +595,7 @@ def handle_streamlit_inference():
subprocess.run(["streamlit", "run", ROOT / "solutions/streamlit_inference.py", "--server.headless", "true"])
-def parse_key_value_pair(pair):
+def parse_key_value_pair(pair: str = "key=value"):
"""
Parses a key-value pair string into separate key and value components.
@@ -650,7 +658,7 @@ def smart_value(v):
Notes:
- The function uses a case-insensitive comparison for boolean and None values.
- - For other types, it attempts to use Python's eval() function, which can be unsafe if used with untrusted input.
+ - For other types, it attempts to use Python's eval() function, which can be unsafe if used on untrusted input.
- If no conversion is possible, the original string is returned.
"""
v_lower = v.lower()
@@ -705,7 +713,7 @@ def entrypoint(debug=""):
"hub": lambda: handle_yolo_hub(args[1:]),
"login": lambda: handle_yolo_hub(args),
"copy-cfg": copy_default_cfg,
- "explorer": lambda: handle_explorer(),
+ "explorer": lambda: handle_explorer(args[1:]),
"streamlit-predict": lambda: handle_streamlit_inference(),
}
full_args_dict = {**DEFAULT_CFG_DICT, **{k: None for k in TASKS}, **{k: None for k in MODES}, **special}
diff --git a/ultralytics/data/annotator.py b/ultralytics/data/annotator.py
index b5b899cf..ccd11b1a 100644
--- a/ultralytics/data/annotator.py
+++ b/ultralytics/data/annotator.py
@@ -9,20 +9,24 @@ def auto_annotate(data, det_model="yolov8x.pt", sam_model="sam_b.pt", device="",
"""
Automatically annotates images using a YOLO object detection model and a SAM segmentation model.
+ This function processes images in a specified directory, detects objects using a YOLO model, and then generates
+ segmentation masks using a SAM model. The resulting annotations are saved as text files.
+
Args:
data (str): Path to a folder containing images to be annotated.
- det_model (str, optional): Pre-trained YOLO detection model. Defaults to 'yolov8x.pt'.
- sam_model (str, optional): Pre-trained SAM segmentation model. Defaults to 'sam_b.pt'.
- device (str, optional): Device to run the models on. Defaults to an empty string (CPU or GPU, if available).
- output_dir (str | None | optional): Directory to save the annotated results.
- Defaults to a 'labels' folder in the same directory as 'data'.
+ det_model (str): Path or name of the pre-trained YOLO detection model.
+ sam_model (str): Path or name of the pre-trained SAM segmentation model.
+ device (str): Device to run the models on (e.g., 'cpu', 'cuda', '0').
+ output_dir (str | None): Directory to save the annotated results. If None, a default directory is created.
- Example:
- ```python
- from ultralytics.data.annotator import auto_annotate
+ Examples:
+ >>> from ultralytics.data.annotator import auto_annotate
+ >>> auto_annotate(data='ultralytics/assets', det_model='yolov8n.pt', sam_model='mobile_sam.pt')
- auto_annotate(data='ultralytics/assets', det_model='yolov8n.pt', sam_model='mobile_sam.pt')
- ```
+ Notes:
+ - The function creates a new directory for output if not specified.
+ - Annotation results are saved as text files with the same names as the input images.
+ - Each line in the output text file represents a detected object with its class ID and segmentation points.
"""
det_model = YOLO(det_model)
sam_model = SAM(sam_model)
diff --git a/ultralytics/data/augment.py b/ultralytics/data/augment.py
index 958d1ac6..90cdd231 100644
--- a/ultralytics/data/augment.py
+++ b/ultralytics/data/augment.py
@@ -159,11 +159,11 @@ class Compose:
tolist: Converts the list of transforms to a standard Python list.
Examples:
- >>> transforms = [RandomFlip(), RandomRotate(30), RandomCrop((224, 224))]
+ >>> transforms = [RandomFlip(), RandomPerspective(30)]
>>> compose = Compose(transforms)
>>> transformed_data = compose(data)
- >>> compose.append(Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]))
- >>> compose.insert(0, Resize((256, 256)))
+ >>> compose.append(CenterCrop((224, 224)))
+ >>> compose.insert(0, RandomFlip())
"""
def __init__(self, transforms):
@@ -174,8 +174,8 @@ class Compose:
transforms (List[Callable]): A list of callable transform objects to be applied sequentially.
Examples:
- >>> from ultralytics.data.augment import Compose, Resize, RandomFlip
- >>> transforms = [Resize(640), RandomFlip()]
+ >>> from ultralytics.data.augment import Compose, RandomHSV, RandomFlip
+ >>> transforms = [RandomHSV(), RandomFlip()]
>>> compose = Compose(transforms)
"""
self.transforms = transforms if isinstance(transforms, list) else [transforms]
@@ -209,7 +209,7 @@ class Compose:
transform (BaseTransform): The transformation to be added to the composition.
Examples:
- >>> compose = Compose([RandomFlip(), RandomRotate()])
+ >>> compose = Compose([RandomFlip(), RandomPerspective()])
>>> compose.append(RandomHSV())
"""
self.transforms.append(transform)
@@ -232,7 +232,7 @@ class Compose:
def __getitem__(self, index: Union[list, int]) -> "Compose":
"""
- Retrieve a specific transform or a set of transforms using indexing.
+ Retrieves a specific transform or a set of transforms using indexing.
Args:
index (int | List[int]): Index or list of indices of the transforms to retrieve.
@@ -244,10 +244,10 @@ class Compose:
AssertionError: If the index is not of type int or list.
Examples:
- >>> transforms = [RandomFlip(), RandomRotate(10), RandomHSV(0.5, 0.5, 0.5)]
+ >>> transforms = [RandomFlip(), RandomPerspective(10), RandomHSV(0.5, 0.5, 0.5)]
>>> compose = Compose(transforms)
- >>> single_transform = compose[1] # Returns a Compose object with only RandomRotate
- >>> multiple_transforms = compose[0:2] # Returns a Compose object with RandomFlip and RandomRotate
+ >>> single_transform = compose[1] # Returns a Compose object with only RandomPerspective
+ >>> multiple_transforms = compose[0:2] # Returns a Compose object with RandomFlip and RandomPerspective
"""
assert isinstance(index, (int, list)), f"The indices should be either list or int type but got {type(index)}"
index = [index] if isinstance(index, int) else index
@@ -288,7 +288,7 @@ class Compose:
(List): A list containing all the transform objects in the Compose instance.
Examples:
- >>> transforms = [RandomFlip(), RandomRotate(10), RandomCrop()]
+ >>> transforms = [RandomFlip(), RandomPerspective(10), CenterCrop()]
>>> compose = Compose(transforms)
>>> transform_list = compose.tolist()
>>> print(len(transform_list))
@@ -304,12 +304,12 @@ class Compose:
(str): A string representation of the Compose object, including the list of transforms.
Examples:
- >>> transforms = [RandomFlip(), RandomAffine(degrees=10, translate=0.1, scale=0.1)]
+ >>> transforms = [RandomFlip(), RandomPerspective(degrees=10, translate=0.1, scale=0.1)]
>>> compose = Compose(transforms)
>>> print(compose)
Compose([
RandomFlip(),
- RandomAffine(degrees=10, translate=0.1, scale=0.1)
+ RandomPerspective(degrees=10, translate=0.1, scale=0.1)
])
"""
return f"{self.__class__.__name__}({', '.join([f'{t}' for t in self.transforms])})"
@@ -353,12 +353,12 @@ class BaseMixTransform:
Args:
dataset (Any): The dataset object containing images and labels for mixing.
- pre_transform (Callable | None): Optional transform to apply before mixing. If None, no pre-transform is applied.
+ pre_transform (Callable | None): Optional transform to apply before mixing.
p (float): Probability of applying the mix transformation. Should be in the range [0.0, 1.0].
Examples:
>>> dataset = YOLODataset("path/to/data")
- >>> pre_transform = Compose([RandomFlip(), RandomRotate()])
+ >>> pre_transform = Compose([RandomFlip(), RandomPerspective()])
>>> mix_transform = BaseMixTransform(dataset, pre_transform, p=0.5)
"""
self.dataset = dataset
@@ -420,7 +420,7 @@ class BaseMixTransform:
(Dict): The modified labels dictionary with augmented data after applying the mix transform.
Examples:
- >>> transform = MixUpTransform(dataset)
+ >>> transform = BaseMixTransform(dataset)
>>> labels = {'image': img, 'bboxes': boxes, 'mix_labels': [{'image': img2, 'bboxes': boxes2}]}
>>> augmented_labels = transform._mix_transform(labels)
"""
@@ -662,13 +662,12 @@ class Mosaic(BaseMixTransform):
updates the corresponding labels for each image in the mosaic.
Args:
- labels (Dict): A dictionary containing image data and labels for the base image (index 0) and
- three additional images (indices 1-3) in the 'mix_labels' key.
+ labels (Dict): A dictionary containing image data and labels for the base image (index 0) and three
+ additional images (indices 1-3) in the 'mix_labels' key.
Returns:
- (Dict): A dictionary containing the mosaic image and updated labels. The 'img' key contains the
- mosaic image as a numpy array, and other keys contain the combined and adjusted labels for
- all four images.
+ (Dict): A dictionary containing the mosaic image and updated labels. The 'img' key contains the mosaic
+ image as a numpy array, and other keys contain the combined and adjusted labels for all four images.
Examples:
>>> mosaic = Mosaic(dataset, imgsz=640, p=1.0, n=4)
@@ -963,7 +962,7 @@ class RandomPerspective:
shear (float): Maximum shear angle in degrees.
perspective (float): Perspective distortion factor.
border (Tuple[int, int]): Mosaic border size as (x, y).
- pre_transform (callable): Optional transform to apply before the random perspective.
+ pre_transform (Callable | None): Optional transform to apply before the random perspective.
Methods:
affine_transform: Applies affine transformations to the input image.
@@ -988,9 +987,8 @@ class RandomPerspective:
"""
Initializes RandomPerspective object with transformation parameters.
- This class implements random perspective and affine transformations on images and corresponding
- bounding boxes, segments, and keypoints. Transformations include rotation, translation, scaling,
- and shearing.
+ This class implements random perspective and affine transformations on images and corresponding bounding boxes,
+ segments, and keypoints. Transformations include rotation, translation, scaling, and shearing.
Args:
degrees (float): Degree range for random rotations.
@@ -999,8 +997,8 @@ class RandomPerspective:
shear (float): Shear intensity (angle in degrees).
perspective (float): Perspective distortion factor.
border (Tuple[int, int]): Tuple specifying mosaic border (top/bottom, left/right).
- pre_transform (Callable | None): Function/transform to apply to the image before starting the
- random transformation.
+ pre_transform (Callable | None): Function/transform to apply to the image before starting the random
+ transformation.
Examples:
>>> transform = RandomPerspective(degrees=10.0, translate=0.1, scale=0.5, shear=5.0)
@@ -1121,8 +1119,8 @@ class RandomPerspective:
the transformed segments. It clips the transformed segments to fit within the new bounding boxes.
Args:
- segments (np.ndarray): Input segments with shape (N, M, 2), where N is the number of segments and M
- is the number of points in each segment.
+ segments (np.ndarray): Input segments with shape (N, M, 2), where N is the number of segments and M is the
+ number of points in each segment.
M (np.ndarray): Affine transformation matrix with shape (3, 3).
Returns:
@@ -1203,10 +1201,10 @@ class RandomPerspective:
Returns:
(Dict): Transformed labels dictionary containing:
- 'img' (ndarray): The transformed image.
- 'cls' (ndarray): Updated class labels.
- 'instances' (Instances): Updated object instances.
- 'resized_shape' (Tuple[int, int]): New image shape after transformation.
+ - 'img' (np.ndarray): The transformed image.
+ - 'cls' (np.ndarray): Updated class labels.
+ - 'instances' (Instances): Updated object instances.
+ - 'resized_shape' (Tuple[int, int]): New image shape after transformation.
Examples:
>>> transform = RandomPerspective()
@@ -1271,9 +1269,9 @@ class RandomPerspective:
been overly distorted or reduced by the augmentation process.
Args:
- box1 (numpy.ndarray): Original boxes before augmentation, shape (4, n) where n is the
+ box1 (numpy.ndarray): Original boxes before augmentation, shape (4, N) where n is the
number of boxes. Format is [x1, y1, x2, y2] in absolute coordinates.
- box2 (numpy.ndarray): Augmented boxes after transformation, shape (4, n). Format is
+ box2 (numpy.ndarray): Augmented boxes after transformation, shape (4, N). Format is
[x1, y1, x2, y2] in absolute coordinates.
wh_thr (float): Width and height threshold in pixels. Boxes smaller than this in either
dimension are rejected.
@@ -1411,9 +1409,8 @@ class RandomFlip:
It also updates any instances (bounding boxes, keypoints, etc.) accordingly.
Args:
- p (float): The probability of applying the flip. Must be between 0 and 1. Default is 0.5.
+ p (float): The probability of applying the flip. Must be between 0 and 1.
direction (str): The direction to apply the flip. Must be 'horizontal' or 'vertical'.
- Default is 'horizontal'.
flip_idx (List[int] | None): Index mapping for flipping keypoints, if any.
Raises:
@@ -1538,15 +1535,15 @@ class LetterBox:
"""
Resizes and pads an image for object detection, instance segmentation, or pose estimation tasks.
- This method applies letterboxing to the input image, which involves resizing the image while maintaining its aspect
- ratio and adding padding to fit the new shape. It also updates any associated labels accordingly.
+ This method applies letterboxing to the input image, which involves resizing the image while maintaining its
+ aspect ratio and adding padding to fit the new shape. It also updates any associated labels accordingly.
Args:
- labels (dict | None): A dictionary containing image data and associated labels. If None, an empty dict is used.
- image (numpy.ndarray | None): The input image as a numpy array. If None, the image is taken from 'labels'.
+ labels (Dict | None): A dictionary containing image data and associated labels, or empty dict if None.
+ image (np.ndarray | None): The input image as a numpy array. If None, the image is taken from 'labels'.
Returns:
- (dict | tuple): If 'labels' is provided, returns an updated dictionary with the resized and padded image,
+ (Dict | Tuple): If 'labels' is provided, returns an updated dictionary with the resized and padded image,
updated labels, and additional metadata. If 'labels' is empty, returns a tuple containing the resized
and padded image, and a tuple of (ratio, (left_pad, top_pad)).
@@ -1675,17 +1672,16 @@ class CopyPaste:
Applies Copy-Paste augmentation to an image and its instances.
Args:
- labels (dict): A dictionary containing:
- - 'img' (numpy.ndarray): The image to augment.
- - 'cls' (numpy.ndarray): Class labels for the instances.
+ labels (Dict): A dictionary containing:
+ - 'img' (np.ndarray): The image to augment.
+ - 'cls' (np.ndarray): Class labels for the instances.
- 'instances' (ultralytics.engine.results.Instances): Object containing bounding boxes, segments, etc.
Returns:
- (dict): Dictionary with augmented image and updated instances under 'img', 'cls', and 'instances' keys.
+ (Dict): Dictionary with augmented image and updated instances under 'img', 'cls', and 'instances' keys.
Examples:
- >>> labels = {'img': np.random.rand(640, 640, 3), 'cls': np.array([0, 1, 2]),
- ... 'instances': Instances(...)}
+ >>> labels = {'img': np.random.rand(640, 640, 3), 'cls': np.array([0, 1, 2]), 'instances': Instances(...)}
>>> augmenter = CopyPaste(p=0.5)
>>> augmented_labels = augmenter(labels)
"""
@@ -1874,8 +1870,12 @@ class Albumentations:
Examples:
>>> transform = Albumentations(p=0.5)
- >>> augmented = transform({"img": np.random.rand(640, 640, 3), "cls": np.array([0, 1]),
- ... "instances": Instances(bboxes=np.array([[0, 0, 1, 1], [0.5, 0.5, 0.8, 0.8]]))})
+ >>> labels = {
+ ... "img": np.random.rand(640, 640, 3),
+ ... "cls": np.array([0, 1]),
+ ... "instances": Instances(bboxes=np.array([[0, 0, 1, 1], [0.5, 0.5, 0.8, 0.8]]))
+ ... }
+ >>> augmented = transform(labels)
>>> assert augmented["img"].shape == (640, 640, 3)
Notes:
@@ -1974,6 +1974,7 @@ class Format:
mask_ratio (int): Downsample ratio for masks.
mask_overlap (bool): Whether masks can overlap.
batch_idx (bool): Whether to keep batch indexes.
+ bgr (float): The probability to return BGR images.
Examples:
>>> format = Format(bbox_format='xyxy', return_mask=True, return_keypoint=False)
@@ -1994,9 +1995,9 @@ class Format:
"""
Formats image annotations for object detection, instance segmentation, and pose estimation tasks.
- This method standardizes the image and instance annotations to be used by the `collate_fn` in PyTorch DataLoader.
- It processes the input labels dictionary, converting annotations to the specified format and applying
- normalization if required.
+ This method standardizes the image and instance annotations to be used by the `collate_fn` in PyTorch
+ DataLoader. It processes the input labels dictionary, converting annotations to the specified format and
+ applying normalization if required.
Args:
labels (Dict): A dictionary containing image and annotation data with the following keys:
@@ -2069,7 +2070,7 @@ class Format:
5. Converts the Numpy array to a PyTorch tensor.
Args:
- img (ndarray): Input image as a Numpy array with shape (H, W, C) or (H, W).
+ img (np.ndarray): Input image as a Numpy array with shape (H, W, C) or (H, W).
Returns:
(torch.Tensor): Formatted image as a PyTorch tensor with shape (C, H, W).
@@ -2130,11 +2131,11 @@ class RandomLoadText:
to reflect the sampled texts and can optionally pad the text list to a fixed length.
Attributes:
- prompt_format (str): Format string for text prompts. Default is '{}'.
- neg_samples (Tuple[int, int]): Range for randomly sampling negative texts. Default is (80, 80).
- max_samples (int): Maximum number of different text samples in one image. Default is 80.
- padding (bool): Whether to pad texts to max_samples. Default is False.
- padding_value (str): The text used for padding when padding is True. Default is "".
+ prompt_format (str): Format string for text prompts.
+ neg_samples (Tuple[int, int]): Range for randomly sampling negative texts.
+ max_samples (int): Maximum number of different text samples in one image.
+ padding (bool): Whether to pad texts to max_samples.
+ padding_value (str): The text used for padding when padding is True.
Methods:
__call__: Processes the input labels and returns updated classes and texts.
@@ -2268,15 +2269,15 @@ def v8_transforms(dataset, imgsz, hyp, stretch=False):
Args:
dataset (Dataset): The dataset object containing image data and annotations.
imgsz (int): The target image size for resizing.
- hyp (dict): A dictionary of hyperparameters controlling various aspects of the transformations.
+ hyp (Dict): A dictionary of hyperparameters controlling various aspects of the transformations.
stretch (bool): If True, applies stretching to the image. If False, uses LetterBox resizing.
Returns:
(Compose): A composition of image transformations to be applied to the dataset.
Examples:
- >>> from ultralytics.data.dataset import Dataset
- >>> dataset = Dataset(img_path='path/to/images', imgsz=640)
+ >>> from ultralytics.data.dataset import YOLODataset
+ >>> dataset = YOLODataset(img_path='path/to/images', imgsz=640)
>>> hyp = {'mosaic': 1.0, 'copy_paste': 0.5, 'degrees': 10.0, 'translate': 0.2, 'scale': 0.9}
>>> transforms = v8_transforms(dataset, imgsz=640, hyp=hyp)
>>> augmented_data = transforms(dataset[0])
@@ -2332,15 +2333,12 @@ def classify_transforms(
center cropping, conversion to tensor, and normalization.
Args:
- size (int | tuple): The target size for the transformed image. If an int, it defines the
- shortest edge. If a tuple, it defines (height, width).
- mean (tuple): Mean values for each RGB channel used in normalization. Defaults to
- DEFAULT_MEAN.
+ size (int | tuple): The target size for the transformed image. If an int, it defines the shortest edge. If a
+ tuple, it defines (height, width).
+ mean (tuple): Mean values for each RGB channel used in normalization.
std (tuple): Standard deviation values for each RGB channel used in normalization.
- Defaults to DEFAULT_STD.
- interpolation (int): Interpolation method for resizing. Defaults to Image.BILINEAR.
- crop_fraction (float): Fraction of the image to be cropped. Defaults to
- DEFAULT_CROP_FRACTION.
+ interpolation (int): Interpolation method for resizing.
+ crop_fraction (float): Fraction of the image to be cropped.
Returns:
(torchvision.transforms.Compose): A composition of torchvision transforms.
@@ -2482,7 +2480,7 @@ def classify_augmentations(
# NOTE: keep this class for backward compatibility
class ClassifyLetterBox:
"""
- YOLOv8 LetterBox class for image preprocessing in classification tasks.
+ A class for resizing and padding images for classification tasks.
This class is designed to be part of a transformation pipeline, e.g., T.Compose([LetterBox(size), ToTensor()]).
It resizes and pads images to a specified size while maintaining the original aspect ratio.
@@ -2512,8 +2510,8 @@ class ClassifyLetterBox:
pads images to a specified size while maintaining the original aspect ratio.
Args:
- size (Union[int, Tuple[int, int]]): Target size for the letterboxed image. If int, a square image of
- (size, size) is created. If tuple, it should be (height, width).
+ size (int | Tuple[int, int]): Target size for the letterboxed image. If an int, a square image of
+ (size, size) is created. If a tuple, it should be (height, width).
auto (bool): If True, automatically calculates the short side based on stride. Default is False.
stride (int): The stride value, used when 'auto' is True. Default is 32.
diff --git a/ultralytics/data/explorer/gui/dash.py b/ultralytics/data/explorer/gui/dash.py
index c66d9a63..81f1f62a 100644
--- a/ultralytics/data/explorer/gui/dash.py
+++ b/ultralytics/data/explorer/gui/dash.py
@@ -1,5 +1,6 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license
+import sys
import time
from threading import Thread
@@ -17,7 +18,8 @@ def _get_explorer():
"""Initializes and returns an instance of the Explorer class."""
exp = Explorer(data=st.session_state.get("dataset"), model=st.session_state.get("model"))
thread = Thread(
- target=exp.create_embeddings_table, kwargs={"force": st.session_state.get("force_recreate_embeddings")}
+ target=exp.create_embeddings_table,
+ kwargs={"force": st.session_state.get("force_recreate_embeddings"), "split": st.session_state.get("split")},
)
thread.start()
progress_bar = st.progress(0, text="Creating embeddings table...")
@@ -29,33 +31,45 @@ def _get_explorer():
progress_bar.empty()
-def init_explorer_form():
+def init_explorer_form(data=None, model=None):
"""Initializes an Explorer instance and creates embeddings table with progress tracking."""
- datasets = ROOT / "cfg" / "datasets"
- ds = [d.name for d in datasets.glob("*.yaml")]
- models = [
- "yolov8n.pt",
- "yolov8s.pt",
- "yolov8m.pt",
- "yolov8l.pt",
- "yolov8x.pt",
- "yolov8n-seg.pt",
- "yolov8s-seg.pt",
- "yolov8m-seg.pt",
- "yolov8l-seg.pt",
- "yolov8x-seg.pt",
- "yolov8n-pose.pt",
- "yolov8s-pose.pt",
- "yolov8m-pose.pt",
- "yolov8l-pose.pt",
- "yolov8x-pose.pt",
- ]
+ if data is None:
+ datasets = ROOT / "cfg" / "datasets"
+ ds = [d.name for d in datasets.glob("*.yaml")]
+ else:
+ ds = [data]
+
+ if model is None:
+ models = [
+ "yolov8n.pt",
+ "yolov8s.pt",
+ "yolov8m.pt",
+ "yolov8l.pt",
+ "yolov8x.pt",
+ "yolov8n-seg.pt",
+ "yolov8s-seg.pt",
+ "yolov8m-seg.pt",
+ "yolov8l-seg.pt",
+ "yolov8x-seg.pt",
+ "yolov8n-pose.pt",
+ "yolov8s-pose.pt",
+ "yolov8m-pose.pt",
+ "yolov8l-pose.pt",
+ "yolov8x-pose.pt",
+ ]
+ else:
+ models = [model]
+
+ splits = ["train", "val", "test"]
+
with st.form(key="explorer_init_form"):
- col1, col2 = st.columns(2)
+ col1, col2, col3 = st.columns(3)
with col1:
- st.selectbox("Select dataset", ds, key="dataset", index=ds.index("coco128.yaml"))
+ st.selectbox("Select dataset", ds, key="dataset")
with col2:
st.selectbox("Select model", models, key="model")
+ with col3:
+ st.selectbox("Select split", splits, key="split")
st.checkbox("Force recreate embeddings", key="force_recreate_embeddings")
st.form_submit_button("Explore", on_click=_get_explorer)
@@ -182,13 +196,13 @@ def utralytics_explorer_docs_callback():
st.link_button("Ultrlaytics Explorer API", "https://docs.ultralytics.com/datasets/explorer/")
-def layout():
+def layout(data=None, model=None):
"""Resets explorer session variables and provides documentation with a link to API docs."""
st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
st.markdown("Ultralytics Explorer Demo
", unsafe_allow_html=True)
if st.session_state.get("explorer") is None:
- init_explorer_form()
+ init_explorer_form(data, model)
return
st.button(":arrow_backward: Select Dataset", on_click=reset_explorer)
@@ -264,4 +278,5 @@ def layout():
if __name__ == "__main__":
- layout()
+ kwargs = dict(zip(sys.argv[1::2], sys.argv[2::2]))
+ layout(**kwargs)
diff --git a/ultralytics/engine/model.py b/ultralytics/engine/model.py
index 85ad8b44..9dc3ae56 100644
--- a/ultralytics/engine/model.py
+++ b/ultralytics/engine/model.py
@@ -583,7 +583,7 @@ class Model(nn.Module):
**kwargs (Any): Additional keyword arguments for configuring the tracking process.
Returns:
- (List[ultralytics.engine.results.Results]): A list of tracking results, each encapsulated in a Results object.
+ (List[ultralytics.engine.results.Results]): A list of tracking results, each a Results object.
Raises:
AttributeError: If the predictor does not have registered trackers.
@@ -1028,8 +1028,8 @@ class Model(nn.Module):
The default callbacks are defined in the 'callbacks.default_callbacks' dictionary, which contains predefined
functions for various events in the model's lifecycle, such as on_train_start, on_epoch_end, etc.
- This method is useful when you want to revert to the original set of callbacks after making custom modifications,
- ensuring consistent behavior across different runs or experiments.
+ This method is useful when you want to revert to the original set of callbacks after making custom
+ modifications, ensuring consistent behavior across different runs or experiments.
Examples:
>>> model = YOLO('yolov8n.pt')
@@ -1122,7 +1122,7 @@ class Model(nn.Module):
nested dictionaries. Each nested dictionary has keys 'model', 'trainer', 'validator', and
'predictor', mapping to their respective class implementations.
- Example:
+ Examples:
>>> model = Model()
>>> task_map = model.task_map
>>> detect_class_map = task_map['detect']