|
@@ -1,1025 +0,0 @@
|
|
-# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
|
|
|
-
|
|
|
|
-import shutil
|
|
|
|
-import subprocess
|
|
|
|
-import sys
|
|
|
|
-from pathlib import Path
|
|
|
|
-from types import SimpleNamespace
|
|
|
|
-from typing import Dict, List, Union
|
|
|
|
-
|
|
|
|
-import cv2
|
|
|
|
-
|
|
|
|
-from ultralytics.utils import (
|
|
|
|
- ASSETS,
|
|
|
|
- DEFAULT_CFG,
|
|
|
|
- DEFAULT_CFG_DICT,
|
|
|
|
- DEFAULT_CFG_PATH,
|
|
|
|
- DEFAULT_SOL_DICT,
|
|
|
|
- IS_VSCODE,
|
|
|
|
- LOGGER,
|
|
|
|
- RANK,
|
|
|
|
- ROOT,
|
|
|
|
- RUNS_DIR,
|
|
|
|
- SETTINGS,
|
|
|
|
- SETTINGS_FILE,
|
|
|
|
- TESTS_RUNNING,
|
|
|
|
- IterableSimpleNamespace,
|
|
|
|
- __version__,
|
|
|
|
- checks,
|
|
|
|
- colorstr,
|
|
|
|
- deprecation_warn,
|
|
|
|
- vscode_msg,
|
|
|
|
- yaml_load,
|
|
|
|
- yaml_print,
|
|
|
|
-)
|
|
|
|
-
|
|
|
|
-# Define valid solutions
|
|
|
|
-SOLUTION_MAP = {
|
|
|
|
- "count": ("ObjectCounter", "count"),
|
|
|
|
- "heatmap": ("Heatmap", "generate_heatmap"),
|
|
|
|
- "queue": ("QueueManager", "process_queue"),
|
|
|
|
- "speed": ("SpeedEstimator", "estimate_speed"),
|
|
|
|
- "workout": ("AIGym", "monitor"),
|
|
|
|
- "analytics": ("Analytics", "process_data"),
|
|
|
|
- "trackzone": ("TrackZone", "trackzone"),
|
|
|
|
- "inference": ("Inference", "inference"),
|
|
|
|
- "help": None,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-# Define valid tasks and modes
|
|
|
|
-MODES = {"train", "val", "predict", "export", "track", "benchmark"}
|
|
|
|
-TASKS = {"detect", "segment", "classify", "pose", "obb"}
|
|
|
|
-TASK2DATA = {
|
|
|
|
- "detect": "coco8.yaml",
|
|
|
|
- "segment": "coco8-seg.yaml",
|
|
|
|
- "classify": "imagenet10",
|
|
|
|
- "pose": "coco8-pose.yaml",
|
|
|
|
- "obb": "dota8.yaml",
|
|
|
|
-}
|
|
|
|
-TASK2MODEL = {
|
|
|
|
- "detect": "yolo11n.pt",
|
|
|
|
- "segment": "yolo11n-seg.pt",
|
|
|
|
- "classify": "yolo11n-cls.pt",
|
|
|
|
- "pose": "yolo11n-pose.pt",
|
|
|
|
- "obb": "yolo11n-obb.pt",
|
|
|
|
-}
|
|
|
|
-TASK2METRIC = {
|
|
|
|
- "detect": "metrics/mAP50-95(B)",
|
|
|
|
- "segment": "metrics/mAP50-95(M)",
|
|
|
|
- "classify": "metrics/accuracy_top1",
|
|
|
|
- "pose": "metrics/mAP50-95(P)",
|
|
|
|
- "obb": "metrics/mAP50-95(B)",
|
|
|
|
-}
|
|
|
|
-MODELS = {TASK2MODEL[task] for task in TASKS}
|
|
|
|
-
|
|
|
|
-ARGV = sys.argv or ["", ""] # sometimes sys.argv = []
|
|
|
|
-SOLUTIONS_HELP_MSG = f"""
|
|
|
|
- Arguments received: {str(["yolo"] + ARGV[1:])}. Ultralytics 'yolo solutions' usage overview:
|
|
|
|
-
|
|
|
|
- yolo solutions SOLUTION ARGS
|
|
|
|
-
|
|
|
|
- Where SOLUTION (optional) is one of {list(SOLUTION_MAP.keys())[:-1]}
|
|
|
|
- ARGS (optional) are any number of custom 'arg=value' pairs like 'show_in=True' that override defaults
|
|
|
|
- at https://docs.ultralytics.com/usage/cfg
|
|
|
|
-
|
|
|
|
- 1. Call object counting solution
|
|
|
|
- yolo solutions count source="path/to/video/file.mp4" region=[(20, 400), (1080, 400), (1080, 360), (20, 360)]
|
|
|
|
-
|
|
|
|
- 2. Call heatmaps solution
|
|
|
|
- yolo solutions heatmap colormap=cv2.COLORMAP_PARULA model=yolo11n.pt
|
|
|
|
-
|
|
|
|
- 3. Call queue management solution
|
|
|
|
- yolo solutions queue region=[(20, 400), (1080, 400), (1080, 360), (20, 360)] model=yolo11n.pt
|
|
|
|
-
|
|
|
|
- 4. Call workouts monitoring solution for push-ups
|
|
|
|
- yolo solutions workout model=yolo11n-pose.pt kpts=[6, 8, 10]
|
|
|
|
-
|
|
|
|
- 5. Generate analytical graphs
|
|
|
|
- yolo solutions analytics analytics_type="pie"
|
|
|
|
-
|
|
|
|
- 6. Track objects within specific zones
|
|
|
|
- yolo solutions trackzone source="path/to/video/file.mp4" region=[(150, 150), (1130, 150), (1130, 570), (150, 570)]
|
|
|
|
-
|
|
|
|
- 7. Streamlit real-time webcam inference GUI
|
|
|
|
- yolo streamlit-predict
|
|
|
|
- """
|
|
|
|
-CLI_HELP_MSG = f"""
|
|
|
|
- Arguments received: {str(["yolo"] + ARGV[1:])}. Ultralytics 'yolo' commands use the following syntax:
|
|
|
|
-
|
|
|
|
- yolo TASK MODE ARGS
|
|
|
|
-
|
|
|
|
- Where TASK (optional) is one of {TASKS}
|
|
|
|
- MODE (required) is one of {MODES}
|
|
|
|
- ARGS (optional) are any number of custom 'arg=value' pairs like 'imgsz=320' that override defaults.
|
|
|
|
- See all ARGS at https://docs.ultralytics.com/usage/cfg or with 'yolo cfg'
|
|
|
|
-
|
|
|
|
- 1. Train a detection model for 10 epochs with an initial learning_rate of 0.01
|
|
|
|
- yolo train data=coco8.yaml model=yolo11n.pt epochs=10 lr0=0.01
|
|
|
|
-
|
|
|
|
- 2. Predict a YouTube video using a pretrained segmentation model at image size 320:
|
|
|
|
- yolo predict model=yolo11n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320
|
|
|
|
-
|
|
|
|
- 3. Val a pretrained detection model at batch-size 1 and image size 640:
|
|
|
|
- yolo val model=yolo11n.pt data=coco8.yaml batch=1 imgsz=640
|
|
|
|
-
|
|
|
|
- 4. Export a YOLO11n classification model to ONNX format at image size 224 by 128 (no TASK required)
|
|
|
|
- yolo export model=yolo11n-cls.pt format=onnx imgsz=224,128
|
|
|
|
-
|
|
|
|
- 5. Ultralytics solutions usage
|
|
|
|
- yolo solutions count or in {list(SOLUTION_MAP.keys())[1:-1]} source="path/to/video/file.mp4"
|
|
|
|
-
|
|
|
|
- 6. Run special commands:
|
|
|
|
- yolo help
|
|
|
|
- yolo checks
|
|
|
|
- yolo version
|
|
|
|
- yolo settings
|
|
|
|
- yolo copy-cfg
|
|
|
|
- yolo cfg
|
|
|
|
- yolo solutions help
|
|
|
|
-
|
|
|
|
- Docs: https://docs.ultralytics.com
|
|
|
|
- Solutions: https://docs.ultralytics.com/solutions/
|
|
|
|
- Community: https://community.ultralytics.com
|
|
|
|
- GitHub: https://github.com/ultralytics/ultralytics
|
|
|
|
- """
|
|
|
|
-
|
|
|
|
-# Define keys for arg type checks
|
|
|
|
-CFG_FLOAT_KEYS = { # integer or float arguments, i.e. x=2 and x=2.0
|
|
|
|
- "warmup_epochs",
|
|
|
|
- "box",
|
|
|
|
- "cls",
|
|
|
|
- "dfl",
|
|
|
|
- "degrees",
|
|
|
|
- "shear",
|
|
|
|
- "time",
|
|
|
|
- "workspace",
|
|
|
|
- "batch",
|
|
|
|
-}
|
|
|
|
-CFG_FRACTION_KEYS = { # fractional float arguments with 0.0<=values<=1.0
|
|
|
|
- "dropout",
|
|
|
|
- "lr0",
|
|
|
|
- "lrf",
|
|
|
|
- "momentum",
|
|
|
|
- "weight_decay",
|
|
|
|
- "warmup_momentum",
|
|
|
|
- "warmup_bias_lr",
|
|
|
|
- "hsv_h",
|
|
|
|
- "hsv_s",
|
|
|
|
- "hsv_v",
|
|
|
|
- "translate",
|
|
|
|
- "scale",
|
|
|
|
- "perspective",
|
|
|
|
- "flipud",
|
|
|
|
- "fliplr",
|
|
|
|
- "bgr",
|
|
|
|
- "mosaic",
|
|
|
|
- "mixup",
|
|
|
|
- "copy_paste",
|
|
|
|
- "conf",
|
|
|
|
- "iou",
|
|
|
|
- "fraction",
|
|
|
|
-}
|
|
|
|
-CFG_INT_KEYS = { # integer-only arguments
|
|
|
|
- "epochs",
|
|
|
|
- "patience",
|
|
|
|
- "workers",
|
|
|
|
- "seed",
|
|
|
|
- "close_mosaic",
|
|
|
|
- "mask_ratio",
|
|
|
|
- "max_det",
|
|
|
|
- "vid_stride",
|
|
|
|
- "line_width",
|
|
|
|
- "nbs",
|
|
|
|
- "save_period",
|
|
|
|
-}
|
|
|
|
-CFG_BOOL_KEYS = { # boolean-only arguments
|
|
|
|
- "save",
|
|
|
|
- "exist_ok",
|
|
|
|
- "verbose",
|
|
|
|
- "deterministic",
|
|
|
|
- "single_cls",
|
|
|
|
- "rect",
|
|
|
|
- "cos_lr",
|
|
|
|
- "overlap_mask",
|
|
|
|
- "val",
|
|
|
|
- "save_json",
|
|
|
|
- "save_hybrid",
|
|
|
|
- "half",
|
|
|
|
- "dnn",
|
|
|
|
- "plots",
|
|
|
|
- "show",
|
|
|
|
- "save_txt",
|
|
|
|
- "save_conf",
|
|
|
|
- "save_crop",
|
|
|
|
- "save_frames",
|
|
|
|
- "show_labels",
|
|
|
|
- "show_conf",
|
|
|
|
- "visualize",
|
|
|
|
- "augment",
|
|
|
|
- "agnostic_nms",
|
|
|
|
- "retina_masks",
|
|
|
|
- "show_boxes",
|
|
|
|
- "keras",
|
|
|
|
- "optimize",
|
|
|
|
- "int8",
|
|
|
|
- "dynamic",
|
|
|
|
- "simplify",
|
|
|
|
- "nms",
|
|
|
|
- "profile",
|
|
|
|
- "multi_scale",
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def cfg2dict(cfg):
|
|
|
|
- """
|
|
|
|
- Converts a configuration object to a dictionary.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- cfg (str | Path | Dict | SimpleNamespace): Configuration object to be converted. Can be a file path,
|
|
|
|
- a string, a dictionary, or a SimpleNamespace object.
|
|
|
|
-
|
|
|
|
- Returns:
|
|
|
|
- (Dict): Configuration object in dictionary format.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- Convert a YAML file path to a dictionary:
|
|
|
|
- >>> config_dict = cfg2dict("config.yaml")
|
|
|
|
-
|
|
|
|
- Convert a SimpleNamespace to a dictionary:
|
|
|
|
- >>> from types import SimpleNamespace
|
|
|
|
- >>> config_sn = SimpleNamespace(param1="value1", param2="value2")
|
|
|
|
- >>> config_dict = cfg2dict(config_sn)
|
|
|
|
-
|
|
|
|
- Pass through an already existing dictionary:
|
|
|
|
- >>> config_dict = cfg2dict({"param1": "value1", "param2": "value2"})
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - If cfg is a path or string, it's loaded as YAML and converted to a dictionary.
|
|
|
|
- - If cfg is a SimpleNamespace object, it's converted to a dictionary using vars().
|
|
|
|
- - If cfg is already a dictionary, it's returned unchanged.
|
|
|
|
- """
|
|
|
|
- if isinstance(cfg, (str, Path)):
|
|
|
|
- cfg = yaml_load(cfg) # load dict
|
|
|
|
- elif isinstance(cfg, SimpleNamespace):
|
|
|
|
- cfg = vars(cfg) # convert to dict
|
|
|
|
- return cfg
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, overrides: Dict = None):
|
|
|
|
- """
|
|
|
|
- Load and merge configuration data from a file or dictionary, with optional overrides.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- cfg (str | Path | Dict | SimpleNamespace): Configuration data source. Can be a file path, dictionary, or
|
|
|
|
- SimpleNamespace object.
|
|
|
|
- overrides (Dict | None): Dictionary containing key-value pairs to override the base configuration.
|
|
|
|
-
|
|
|
|
- Returns:
|
|
|
|
- (SimpleNamespace): Namespace containing the merged configuration arguments.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> from ultralytics.cfg import get_cfg
|
|
|
|
- >>> config = get_cfg() # Load default configuration
|
|
|
|
- >>> config_with_overrides = get_cfg("path/to/config.yaml", overrides={"epochs": 50, "batch_size": 16})
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - If both `cfg` and `overrides` are provided, the values in `overrides` will take precedence.
|
|
|
|
- - Special handling ensures alignment and correctness of the configuration, such as converting numeric
|
|
|
|
- `project` and `name` to strings and validating configuration keys and values.
|
|
|
|
- - The function performs type and value checks on the configuration data.
|
|
|
|
- """
|
|
|
|
- cfg = cfg2dict(cfg)
|
|
|
|
-
|
|
|
|
- # Merge overrides
|
|
|
|
- if overrides:
|
|
|
|
- overrides = cfg2dict(overrides)
|
|
|
|
- if "save_dir" not in cfg:
|
|
|
|
- overrides.pop("save_dir", None) # special override keys to ignore
|
|
|
|
- check_dict_alignment(cfg, overrides)
|
|
|
|
- cfg = {**cfg, **overrides} # merge cfg and overrides dicts (prefer overrides)
|
|
|
|
-
|
|
|
|
- # Special handling for numeric project/name
|
|
|
|
- for k in "project", "name":
|
|
|
|
- if k in cfg and isinstance(cfg[k], (int, float)):
|
|
|
|
- cfg[k] = str(cfg[k])
|
|
|
|
- if cfg.get("name") == "model": # assign model to 'name' arg
|
|
|
|
- cfg["name"] = str(cfg.get("model", "")).split(".")[0]
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ 'name=model' automatically updated to 'name={cfg['name']}'.")
|
|
|
|
-
|
|
|
|
- # Type and Value checks
|
|
|
|
- check_cfg(cfg)
|
|
|
|
-
|
|
|
|
- # Return instance
|
|
|
|
- return IterableSimpleNamespace(**cfg)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def check_cfg(cfg, hard=True):
|
|
|
|
- """
|
|
|
|
- Checks configuration argument types and values for the Ultralytics library.
|
|
|
|
-
|
|
|
|
- This function validates the types and values of configuration arguments, ensuring correctness and converting
|
|
|
|
- them if necessary. It checks for specific key types defined in global variables such as CFG_FLOAT_KEYS,
|
|
|
|
- CFG_FRACTION_KEYS, CFG_INT_KEYS, and CFG_BOOL_KEYS.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- cfg (Dict): Configuration dictionary to validate.
|
|
|
|
- hard (bool): If True, raises exceptions for invalid types and values; if False, attempts to convert them.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> config = {
|
|
|
|
- ... "epochs": 50, # valid integer
|
|
|
|
- ... "lr0": 0.01, # valid float
|
|
|
|
- ... "momentum": 1.2, # invalid float (out of 0.0-1.0 range)
|
|
|
|
- ... "save": "true", # invalid bool
|
|
|
|
- ... }
|
|
|
|
- >>> check_cfg(config, hard=False)
|
|
|
|
- >>> print(config)
|
|
|
|
- {'epochs': 50, 'lr0': 0.01, 'momentum': 1.2, 'save': False} # corrected 'save' key
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - The function modifies the input dictionary in-place.
|
|
|
|
- - None values are ignored as they may be from optional arguments.
|
|
|
|
- - Fraction keys are checked to be within the range [0.0, 1.0].
|
|
|
|
- """
|
|
|
|
- for k, v in cfg.items():
|
|
|
|
- if v is not None: # None values may be from optional args
|
|
|
|
- if k in CFG_FLOAT_KEYS and not isinstance(v, (int, float)):
|
|
|
|
- if hard:
|
|
|
|
- raise TypeError(
|
|
|
|
- f"'{k}={v}' is of invalid type {type(v).__name__}. "
|
|
|
|
- f"Valid '{k}' types are int (i.e. '{k}=0') or float (i.e. '{k}=0.5')"
|
|
|
|
- )
|
|
|
|
- cfg[k] = float(v)
|
|
|
|
- elif k in CFG_FRACTION_KEYS:
|
|
|
|
- if not isinstance(v, (int, float)):
|
|
|
|
- if hard:
|
|
|
|
- raise TypeError(
|
|
|
|
- f"'{k}={v}' is of invalid type {type(v).__name__}. "
|
|
|
|
- f"Valid '{k}' types are int (i.e. '{k}=0') or float (i.e. '{k}=0.5')"
|
|
|
|
- )
|
|
|
|
- cfg[k] = v = float(v)
|
|
|
|
- if not (0.0 <= v <= 1.0):
|
|
|
|
- raise ValueError(f"'{k}={v}' is an invalid value. Valid '{k}' values are between 0.0 and 1.0.")
|
|
|
|
- elif k in CFG_INT_KEYS and not isinstance(v, int):
|
|
|
|
- if hard:
|
|
|
|
- raise TypeError(
|
|
|
|
- f"'{k}={v}' is of invalid type {type(v).__name__}. '{k}' must be an int (i.e. '{k}=8')"
|
|
|
|
- )
|
|
|
|
- cfg[k] = int(v)
|
|
|
|
- elif k in CFG_BOOL_KEYS and not isinstance(v, bool):
|
|
|
|
- if hard:
|
|
|
|
- raise TypeError(
|
|
|
|
- f"'{k}={v}' is of invalid type {type(v).__name__}. "
|
|
|
|
- f"'{k}' must be a bool (i.e. '{k}=True' or '{k}=False')"
|
|
|
|
- )
|
|
|
|
- cfg[k] = bool(v)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def get_save_dir(args, name=None):
|
|
|
|
- """
|
|
|
|
- Returns the directory path for saving outputs, derived from arguments or default settings.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- args (SimpleNamespace): Namespace object containing configurations such as 'project', 'name', 'task',
|
|
|
|
- 'mode', and 'save_dir'.
|
|
|
|
- name (str | None): Optional name for the output directory. If not provided, it defaults to 'args.name'
|
|
|
|
- or the 'args.mode'.
|
|
|
|
-
|
|
|
|
- Returns:
|
|
|
|
- (Path): Directory path where outputs should be saved.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> from types import SimpleNamespace
|
|
|
|
- >>> args = SimpleNamespace(project="my_project", task="detect", mode="train", exist_ok=True)
|
|
|
|
- >>> save_dir = get_save_dir(args)
|
|
|
|
- >>> print(save_dir)
|
|
|
|
- my_project/detect/train
|
|
|
|
- """
|
|
|
|
- if getattr(args, "save_dir", None):
|
|
|
|
- save_dir = args.save_dir
|
|
|
|
- else:
|
|
|
|
- from ultralytics.utils.files import increment_path
|
|
|
|
-
|
|
|
|
- project = args.project or (ROOT.parent / "tests/tmp/runs" if TESTS_RUNNING else RUNS_DIR) / args.task
|
|
|
|
- name = name or args.name or f"{args.mode}"
|
|
|
|
- save_dir = increment_path(Path(project) / name, exist_ok=args.exist_ok if RANK in {-1, 0} else True)
|
|
|
|
-
|
|
|
|
- return Path(save_dir)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def _handle_deprecation(custom):
|
|
|
|
- """
|
|
|
|
- Handles deprecated configuration keys by mapping them to current equivalents with deprecation warnings.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- custom (Dict): Configuration dictionary potentially containing deprecated keys.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> custom_config = {"boxes": True, "hide_labels": "False", "line_thickness": 2}
|
|
|
|
- >>> _handle_deprecation(custom_config)
|
|
|
|
- >>> print(custom_config)
|
|
|
|
- {'show_boxes': True, 'show_labels': True, 'line_width': 2}
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- This function modifies the input dictionary in-place, replacing deprecated keys with their current
|
|
|
|
- equivalents. It also handles value conversions where necessary, such as inverting boolean values for
|
|
|
|
- 'hide_labels' and 'hide_conf'.
|
|
|
|
- """
|
|
|
|
- for key in custom.copy().keys():
|
|
|
|
- if key == "boxes":
|
|
|
|
- deprecation_warn(key, "show_boxes")
|
|
|
|
- custom["show_boxes"] = custom.pop("boxes")
|
|
|
|
- if key == "hide_labels":
|
|
|
|
- deprecation_warn(key, "show_labels")
|
|
|
|
- custom["show_labels"] = custom.pop("hide_labels") == "False"
|
|
|
|
- if key == "hide_conf":
|
|
|
|
- deprecation_warn(key, "show_conf")
|
|
|
|
- custom["show_conf"] = custom.pop("hide_conf") == "False"
|
|
|
|
- if key == "line_thickness":
|
|
|
|
- deprecation_warn(key, "line_width")
|
|
|
|
- custom["line_width"] = custom.pop("line_thickness")
|
|
|
|
- if key == "label_smoothing":
|
|
|
|
- deprecation_warn(key)
|
|
|
|
- custom.pop("label_smoothing")
|
|
|
|
-
|
|
|
|
- return custom
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def check_dict_alignment(base: Dict, custom: Dict, e=None):
|
|
|
|
- """
|
|
|
|
- Checks alignment between custom and base configuration dictionaries, handling deprecated keys and providing error
|
|
|
|
- messages for mismatched keys.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- base (Dict): The base configuration dictionary containing valid keys.
|
|
|
|
- custom (Dict): The custom configuration dictionary to be checked for alignment.
|
|
|
|
- e (Exception | None): Optional error instance passed by the calling function.
|
|
|
|
-
|
|
|
|
- Raises:
|
|
|
|
- SystemExit: If mismatched keys are found between the custom and base dictionaries.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> base_cfg = {"epochs": 50, "lr0": 0.01, "batch_size": 16}
|
|
|
|
- >>> custom_cfg = {"epoch": 100, "lr": 0.02, "batch_size": 32}
|
|
|
|
- >>> try:
|
|
|
|
- ... check_dict_alignment(base_cfg, custom_cfg)
|
|
|
|
- ... except SystemExit:
|
|
|
|
- ... print("Mismatched keys found")
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - Suggests corrections for mismatched keys based on similarity to valid keys.
|
|
|
|
- - Automatically replaces deprecated keys in the custom configuration with updated equivalents.
|
|
|
|
- - Prints detailed error messages for each mismatched key to help users correct their configurations.
|
|
|
|
- """
|
|
|
|
- custom = _handle_deprecation(custom)
|
|
|
|
- base_keys, custom_keys = (set(x.keys()) for x in (base, custom))
|
|
|
|
- if mismatched := [k for k in custom_keys if k not in base_keys]:
|
|
|
|
- from difflib import get_close_matches
|
|
|
|
-
|
|
|
|
- string = ""
|
|
|
|
- for x in mismatched:
|
|
|
|
- matches = get_close_matches(x, base_keys) # key list
|
|
|
|
- matches = [f"{k}={base[k]}" if base.get(k) is not None else k for k in matches]
|
|
|
|
- match_str = f"Similar arguments are i.e. {matches}." if matches else ""
|
|
|
|
- string += f"'{colorstr('red', 'bold', x)}' is not a valid YOLO argument. {match_str}\n"
|
|
|
|
- raise SyntaxError(string + CLI_HELP_MSG) from e
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def merge_equals_args(args: List[str]) -> List[str]:
|
|
|
|
- """
|
|
|
|
- Merges arguments around isolated '=' in a list of strings and joins fragments with brackets.
|
|
|
|
-
|
|
|
|
- This function handles the following cases:
|
|
|
|
- 1. ['arg', '=', 'val'] becomes ['arg=val']
|
|
|
|
- 2. ['arg=', 'val'] becomes ['arg=val']
|
|
|
|
- 3. ['arg', '=val'] becomes ['arg=val']
|
|
|
|
- 4. Joins fragments with brackets, e.g., ['imgsz=[3,', '640,', '640]'] becomes ['imgsz=[3,640,640]']
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- args (List[str]): A list of strings where each element represents an argument or fragment.
|
|
|
|
-
|
|
|
|
- Returns:
|
|
|
|
- List[str]: A list of strings where the arguments around isolated '=' are merged and fragments with brackets are joined.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> args = ["arg1", "=", "value", "arg2=", "value2", "arg3", "=value3", "imgsz=[3,", "640,", "640]"]
|
|
|
|
- >>> merge_and_join_args(args)
|
|
|
|
- ['arg1=value', 'arg2=value2', 'arg3=value3', 'imgsz=[3,640,640]']
|
|
|
|
- """
|
|
|
|
- new_args = []
|
|
|
|
- current = ""
|
|
|
|
- depth = 0
|
|
|
|
-
|
|
|
|
- i = 0
|
|
|
|
- while i < len(args):
|
|
|
|
- arg = args[i]
|
|
|
|
-
|
|
|
|
- # Handle equals sign merging
|
|
|
|
- if arg == "=" and 0 < i < len(args) - 1: # merge ['arg', '=', 'val']
|
|
|
|
- new_args[-1] += f"={args[i + 1]}"
|
|
|
|
- i += 2
|
|
|
|
- continue
|
|
|
|
- elif arg.endswith("=") and i < len(args) - 1 and "=" not in args[i + 1]: # merge ['arg=', 'val']
|
|
|
|
- new_args.append(f"{arg}{args[i + 1]}")
|
|
|
|
- i += 2
|
|
|
|
- continue
|
|
|
|
- elif arg.startswith("=") and i > 0: # merge ['arg', '=val']
|
|
|
|
- new_args[-1] += arg
|
|
|
|
- i += 1
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- # Handle bracket joining
|
|
|
|
- depth += arg.count("[") - arg.count("]")
|
|
|
|
- current += arg
|
|
|
|
- if depth == 0:
|
|
|
|
- new_args.append(current)
|
|
|
|
- current = ""
|
|
|
|
-
|
|
|
|
- i += 1
|
|
|
|
-
|
|
|
|
- # Append any remaining current string
|
|
|
|
- if current:
|
|
|
|
- new_args.append(current)
|
|
|
|
-
|
|
|
|
- return new_args
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def handle_yolo_hub(args: List[str]) -> None:
|
|
|
|
- """
|
|
|
|
- Handles Ultralytics HUB command-line interface (CLI) commands for authentication.
|
|
|
|
-
|
|
|
|
- This function processes Ultralytics HUB CLI commands such as login and logout. It should be called when executing a
|
|
|
|
- script with arguments related to HUB authentication.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- args (List[str]): A list of command line arguments. The first argument should be either 'login'
|
|
|
|
- or 'logout'. For 'login', an optional second argument can be the API key.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- ```bash
|
|
|
|
- yolo login YOUR_API_KEY
|
|
|
|
- ```
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - The function imports the 'hub' module from ultralytics to perform login and logout operations.
|
|
|
|
- - For the 'login' command, if no API key is provided, an empty string is passed to the login function.
|
|
|
|
- - The 'logout' command does not require any additional arguments.
|
|
|
|
- """
|
|
|
|
- from ultralytics import hub
|
|
|
|
-
|
|
|
|
- if args[0] == "login":
|
|
|
|
- key = args[1] if len(args) > 1 else ""
|
|
|
|
- # Log in to Ultralytics HUB using the provided API key
|
|
|
|
- hub.login(key)
|
|
|
|
- elif args[0] == "logout":
|
|
|
|
- # Log out from Ultralytics HUB
|
|
|
|
- hub.logout()
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def handle_yolo_settings(args: List[str]) -> None:
|
|
|
|
- """
|
|
|
|
- Handles YOLO settings command-line interface (CLI) commands.
|
|
|
|
-
|
|
|
|
- This function processes YOLO settings CLI commands such as reset and updating individual settings. It should be
|
|
|
|
- called when executing a script with arguments related to YOLO settings management.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- args (List[str]): A list of command line arguments for YOLO settings management.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> handle_yolo_settings(["reset"]) # Reset YOLO settings
|
|
|
|
- >>> handle_yolo_settings(["default_cfg_path=yolo11n.yaml"]) # Update a specific setting
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - If no arguments are provided, the function will display the current settings.
|
|
|
|
- - The 'reset' command will delete the existing settings file and create new default settings.
|
|
|
|
- - Other arguments are treated as key-value pairs to update specific settings.
|
|
|
|
- - The function will check for alignment between the provided settings and the existing ones.
|
|
|
|
- - After processing, the updated settings will be displayed.
|
|
|
|
- - For more information on handling YOLO settings, visit:
|
|
|
|
- https://docs.ultralytics.com/quickstart/#ultralytics-settings
|
|
|
|
- """
|
|
|
|
- url = "https://docs.ultralytics.com/quickstart/#ultralytics-settings" # help URL
|
|
|
|
- try:
|
|
|
|
- if any(args):
|
|
|
|
- if args[0] == "reset":
|
|
|
|
- SETTINGS_FILE.unlink() # delete the settings file
|
|
|
|
- SETTINGS.reset() # create new settings
|
|
|
|
- LOGGER.info("Settings reset successfully") # inform the user that settings have been reset
|
|
|
|
- else: # save a new setting
|
|
|
|
- new = dict(parse_key_value_pair(a) for a in args)
|
|
|
|
- check_dict_alignment(SETTINGS, new)
|
|
|
|
- SETTINGS.update(new)
|
|
|
|
-
|
|
|
|
- print(SETTINGS) # print the current settings
|
|
|
|
- LOGGER.info(f"💡 Learn more about Ultralytics Settings at {url}")
|
|
|
|
- except Exception as e:
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ settings error: '{e}'. Please see {url} for help.")
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def handle_yolo_solutions(args: List[str]) -> None:
|
|
|
|
- """
|
|
|
|
- Processes YOLO solutions arguments and runs the specified computer vision solutions pipeline.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- args (List[str]): Command-line arguments for configuring and running the Ultralytics YOLO
|
|
|
|
- solutions: https://docs.ultralytics.com/solutions/, It can include solution name, source,
|
|
|
|
- and other configuration parameters.
|
|
|
|
-
|
|
|
|
- Returns:
|
|
|
|
- None: The function processes video frames and saves the output but doesn't return any value.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- Run people counting solution with default settings:
|
|
|
|
- >>> handle_yolo_solutions(["count"])
|
|
|
|
-
|
|
|
|
- Run analytics with custom configuration:
|
|
|
|
- >>> handle_yolo_solutions(["analytics", "conf=0.25", "source=path/to/video/file.mp4"])
|
|
|
|
-
|
|
|
|
- Run inference with custom configuration, requires Streamlit version 1.29.0 or higher.
|
|
|
|
- >>> handle_yolo_solutions(["inference", "model=yolo11n.pt"])
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - Default configurations are merged from DEFAULT_SOL_DICT and DEFAULT_CFG_DICT
|
|
|
|
- - Arguments can be provided in the format 'key=value' or as boolean flags
|
|
|
|
- - Available solutions are defined in SOLUTION_MAP with their respective classes and methods
|
|
|
|
- - If an invalid solution is provided, defaults to 'count' solution
|
|
|
|
- - Output videos are saved in 'runs/solution/{solution_name}' directory
|
|
|
|
- - For 'analytics' solution, frame numbers are tracked for generating analytical graphs
|
|
|
|
- - Video processing can be interrupted by pressing 'q'
|
|
|
|
- - Processes video frames sequentially and saves output in .avi format
|
|
|
|
- - If no source is specified, downloads and uses a default sample video\
|
|
|
|
- - The inference solution will be launched using the 'streamlit run' command.
|
|
|
|
- - The Streamlit app file is located in the Ultralytics package directory.
|
|
|
|
- """
|
|
|
|
- full_args_dict = {**DEFAULT_SOL_DICT, **DEFAULT_CFG_DICT} # arguments dictionary
|
|
|
|
- overrides = {}
|
|
|
|
-
|
|
|
|
- # check dictionary alignment
|
|
|
|
- for arg in merge_equals_args(args):
|
|
|
|
- arg = arg.lstrip("-").rstrip(",")
|
|
|
|
- if "=" in arg:
|
|
|
|
- try:
|
|
|
|
- k, v = parse_key_value_pair(arg)
|
|
|
|
- overrides[k] = v
|
|
|
|
- except (NameError, SyntaxError, ValueError, AssertionError) as e:
|
|
|
|
- check_dict_alignment(full_args_dict, {arg: ""}, e)
|
|
|
|
- elif arg in full_args_dict and isinstance(full_args_dict.get(arg), bool):
|
|
|
|
- overrides[arg] = True
|
|
|
|
- check_dict_alignment(full_args_dict, overrides) # dict alignment
|
|
|
|
-
|
|
|
|
- # Get solution name
|
|
|
|
- if args and args[0] in SOLUTION_MAP:
|
|
|
|
- if args[0] != "help":
|
|
|
|
- s_n = args.pop(0) # Extract the solution name directly
|
|
|
|
- else:
|
|
|
|
- LOGGER.info(SOLUTIONS_HELP_MSG)
|
|
|
|
- else:
|
|
|
|
- LOGGER.warning(
|
|
|
|
- f"⚠️ No valid solution provided. Using default 'count'. Available: {', '.join(SOLUTION_MAP.keys())}"
|
|
|
|
- )
|
|
|
|
- s_n = "count" # Default solution if none provided
|
|
|
|
-
|
|
|
|
- if args and args[0] == "help": # Add check for return if user call `yolo solutions help`
|
|
|
|
- return
|
|
|
|
-
|
|
|
|
- if s_n == "inference":
|
|
|
|
- checks.check_requirements("streamlit>=1.29.0")
|
|
|
|
- LOGGER.info("💡 Loading Ultralytics live inference app...")
|
|
|
|
- subprocess.run(
|
|
|
|
- [ # Run subprocess with Streamlit custom argument
|
|
|
|
- "streamlit",
|
|
|
|
- "run",
|
|
|
|
- str(ROOT / "solutions/streamlit_inference.py"),
|
|
|
|
- "--server.headless",
|
|
|
|
- "true",
|
|
|
|
- overrides.pop("model", "yolo11n.pt"),
|
|
|
|
- ]
|
|
|
|
- )
|
|
|
|
- else:
|
|
|
|
- cls, method = SOLUTION_MAP[s_n] # solution class name, method name and default source
|
|
|
|
-
|
|
|
|
- from ultralytics import solutions # import ultralytics solutions
|
|
|
|
-
|
|
|
|
- solution = getattr(solutions, cls)(IS_CLI=True, **overrides) # get solution class i.e ObjectCounter
|
|
|
|
- process = getattr(
|
|
|
|
- solution, method
|
|
|
|
- ) # get specific function of class for processing i.e, count from ObjectCounter
|
|
|
|
-
|
|
|
|
- cap = cv2.VideoCapture(solution.CFG["source"]) # read the video file
|
|
|
|
-
|
|
|
|
- # extract width, height and fps of the video file, create save directory and initialize video writer
|
|
|
|
- import os # for directory creation
|
|
|
|
- from pathlib import Path
|
|
|
|
-
|
|
|
|
- from ultralytics.utils.files import increment_path # for output directory path update
|
|
|
|
-
|
|
|
|
- w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS))
|
|
|
|
- if s_n == "analytics": # analytical graphs follow fixed shape for output i.e w=1920, h=1080
|
|
|
|
- w, h = 1920, 1080
|
|
|
|
- save_dir = increment_path(Path("runs") / "solutions" / "exp", exist_ok=False)
|
|
|
|
- save_dir.mkdir(parents=True, exist_ok=True) # create the output directory
|
|
|
|
- vw = cv2.VideoWriter(os.path.join(save_dir, "solution.avi"), cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
|
|
|
|
-
|
|
|
|
- try: # Process video frames
|
|
|
|
- f_n = 0 # frame number, required for analytical graphs
|
|
|
|
- while cap.isOpened():
|
|
|
|
- success, frame = cap.read()
|
|
|
|
- if not success:
|
|
|
|
- break
|
|
|
|
- frame = process(frame, f_n := f_n + 1) if s_n == "analytics" else process(frame)
|
|
|
|
- vw.write(frame)
|
|
|
|
- if cv2.waitKey(1) & 0xFF == ord("q"):
|
|
|
|
- break
|
|
|
|
- finally:
|
|
|
|
- cap.release()
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def parse_key_value_pair(pair: str = "key=value"):
|
|
|
|
- """
|
|
|
|
- Parses a key-value pair string into separate key and value components.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- pair (str): A string containing a key-value pair in the format "key=value".
|
|
|
|
-
|
|
|
|
- Returns:
|
|
|
|
- key (str): The parsed key.
|
|
|
|
- value (str): The parsed value.
|
|
|
|
-
|
|
|
|
- Raises:
|
|
|
|
- AssertionError: If the value is missing or empty.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> key, value = parse_key_value_pair("model=yolo11n.pt")
|
|
|
|
- >>> print(f"Key: {key}, Value: {value}")
|
|
|
|
- Key: model, Value: yolo11n.pt
|
|
|
|
-
|
|
|
|
- >>> key, value = parse_key_value_pair("epochs=100")
|
|
|
|
- >>> print(f"Key: {key}, Value: {value}")
|
|
|
|
- Key: epochs, Value: 100
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - The function splits the input string on the first '=' character.
|
|
|
|
- - Leading and trailing whitespace is removed from both key and value.
|
|
|
|
- - An assertion error is raised if the value is empty after stripping.
|
|
|
|
- """
|
|
|
|
- k, v = pair.split("=", 1) # split on first '=' sign
|
|
|
|
- k, v = k.strip(), v.strip() # remove spaces
|
|
|
|
- assert v, f"missing '{k}' value"
|
|
|
|
- return k, smart_value(v)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def smart_value(v):
|
|
|
|
- """
|
|
|
|
- Converts a string representation of a value to its appropriate Python type.
|
|
|
|
-
|
|
|
|
- This function attempts to convert a given string into a Python object of the most appropriate type. It handles
|
|
|
|
- conversions to None, bool, int, float, and other types that can be evaluated safely.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- v (str): The string representation of the value to be converted.
|
|
|
|
-
|
|
|
|
- Returns:
|
|
|
|
- (Any): The converted value. The type can be None, bool, int, float, or the original string if no conversion
|
|
|
|
- is applicable.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> smart_value("42")
|
|
|
|
- 42
|
|
|
|
- >>> smart_value("3.14")
|
|
|
|
- 3.14
|
|
|
|
- >>> smart_value("True")
|
|
|
|
- True
|
|
|
|
- >>> smart_value("None")
|
|
|
|
- None
|
|
|
|
- >>> smart_value("some_string")
|
|
|
|
- 'some_string'
|
|
|
|
-
|
|
|
|
- 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 on untrusted input.
|
|
|
|
- - If no conversion is possible, the original string is returned.
|
|
|
|
- """
|
|
|
|
- v_lower = v.lower()
|
|
|
|
- if v_lower == "none":
|
|
|
|
- return None
|
|
|
|
- elif v_lower == "true":
|
|
|
|
- return True
|
|
|
|
- elif v_lower == "false":
|
|
|
|
- return False
|
|
|
|
- else:
|
|
|
|
- try:
|
|
|
|
- return eval(v)
|
|
|
|
- except Exception:
|
|
|
|
- return v
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def entrypoint(debug=""):
|
|
|
|
- """
|
|
|
|
- Ultralytics entrypoint function for parsing and executing command-line arguments.
|
|
|
|
-
|
|
|
|
- This function serves as the main entry point for the Ultralytics CLI, parsing command-line arguments and
|
|
|
|
- executing the corresponding tasks such as training, validation, prediction, exporting models, and more.
|
|
|
|
-
|
|
|
|
- Args:
|
|
|
|
- debug (str): Space-separated string of command-line arguments for debugging purposes.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- Train a detection model for 10 epochs with an initial learning_rate of 0.01:
|
|
|
|
- >>> entrypoint("train data=coco8.yaml model=yolo11n.pt epochs=10 lr0=0.01")
|
|
|
|
-
|
|
|
|
- Predict a YouTube video using a pretrained segmentation model at image size 320:
|
|
|
|
- >>> entrypoint("predict model=yolo11n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320")
|
|
|
|
-
|
|
|
|
- Validate a pretrained detection model at batch-size 1 and image size 640:
|
|
|
|
- >>> entrypoint("val model=yolo11n.pt data=coco8.yaml batch=1 imgsz=640")
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - If no arguments are passed, the function will display the usage help message.
|
|
|
|
- - For a list of all available commands and their arguments, see the provided help messages and the
|
|
|
|
- Ultralytics documentation at https://docs.ultralytics.com.
|
|
|
|
- """
|
|
|
|
- args = (debug.split(" ") if debug else ARGV)[1:]
|
|
|
|
- if not args: # no arguments passed
|
|
|
|
- LOGGER.info(CLI_HELP_MSG)
|
|
|
|
- return
|
|
|
|
-
|
|
|
|
- special = {
|
|
|
|
- "help": lambda: LOGGER.info(CLI_HELP_MSG),
|
|
|
|
- "checks": checks.collect_system_info,
|
|
|
|
- "version": lambda: LOGGER.info(__version__),
|
|
|
|
- "settings": lambda: handle_yolo_settings(args[1:]),
|
|
|
|
- "cfg": lambda: yaml_print(DEFAULT_CFG_PATH),
|
|
|
|
- "hub": lambda: handle_yolo_hub(args[1:]),
|
|
|
|
- "login": lambda: handle_yolo_hub(args),
|
|
|
|
- "logout": lambda: handle_yolo_hub(args),
|
|
|
|
- "copy-cfg": copy_default_cfg,
|
|
|
|
- "solutions": lambda: handle_yolo_solutions(args[1:]),
|
|
|
|
- }
|
|
|
|
- full_args_dict = {**DEFAULT_CFG_DICT, **{k: None for k in TASKS}, **{k: None for k in MODES}, **special}
|
|
|
|
-
|
|
|
|
- # Define common misuses of special commands, i.e. -h, -help, --help
|
|
|
|
- special.update({k[0]: v for k, v in special.items()}) # singular
|
|
|
|
- special.update({k[:-1]: v for k, v in special.items() if len(k) > 1 and k.endswith("s")}) # singular
|
|
|
|
- special = {**special, **{f"-{k}": v for k, v in special.items()}, **{f"--{k}": v for k, v in special.items()}}
|
|
|
|
-
|
|
|
|
- overrides = {} # basic overrides, i.e. imgsz=320
|
|
|
|
- for a in merge_equals_args(args): # merge spaces around '=' sign
|
|
|
|
- if a.startswith("--"):
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ argument '{a}' does not require leading dashes '--', updating to '{a[2:]}'.")
|
|
|
|
- a = a[2:]
|
|
|
|
- if a.endswith(","):
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ argument '{a}' does not require trailing comma ',', updating to '{a[:-1]}'.")
|
|
|
|
- a = a[:-1]
|
|
|
|
- if "=" in a:
|
|
|
|
- try:
|
|
|
|
- k, v = parse_key_value_pair(a)
|
|
|
|
- if k == "cfg" and v is not None: # custom.yaml passed
|
|
|
|
- LOGGER.info(f"Overriding {DEFAULT_CFG_PATH} with {v}")
|
|
|
|
- overrides = {k: val for k, val in yaml_load(checks.check_yaml(v)).items() if k != "cfg"}
|
|
|
|
- else:
|
|
|
|
- overrides[k] = v
|
|
|
|
- except (NameError, SyntaxError, ValueError, AssertionError) as e:
|
|
|
|
- check_dict_alignment(full_args_dict, {a: ""}, e)
|
|
|
|
-
|
|
|
|
- elif a in TASKS:
|
|
|
|
- overrides["task"] = a
|
|
|
|
- elif a in MODES:
|
|
|
|
- overrides["mode"] = a
|
|
|
|
- elif a.lower() in special:
|
|
|
|
- special[a.lower()]()
|
|
|
|
- return
|
|
|
|
- elif a in DEFAULT_CFG_DICT and isinstance(DEFAULT_CFG_DICT[a], bool):
|
|
|
|
- overrides[a] = True # auto-True for default bool args, i.e. 'yolo show' sets show=True
|
|
|
|
- elif a in DEFAULT_CFG_DICT:
|
|
|
|
- raise SyntaxError(
|
|
|
|
- f"'{colorstr('red', 'bold', a)}' is a valid YOLO argument but is missing an '=' sign "
|
|
|
|
- f"to set its value, i.e. try '{a}={DEFAULT_CFG_DICT[a]}'\n{CLI_HELP_MSG}"
|
|
|
|
- )
|
|
|
|
- else:
|
|
|
|
- check_dict_alignment(full_args_dict, {a: ""})
|
|
|
|
-
|
|
|
|
- # Check keys
|
|
|
|
- check_dict_alignment(full_args_dict, overrides)
|
|
|
|
-
|
|
|
|
- # Mode
|
|
|
|
- mode = overrides.get("mode")
|
|
|
|
- if mode is None:
|
|
|
|
- mode = DEFAULT_CFG.mode or "predict"
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ 'mode' argument is missing. Valid modes are {MODES}. Using default 'mode={mode}'.")
|
|
|
|
- elif mode not in MODES:
|
|
|
|
- raise ValueError(f"Invalid 'mode={mode}'. Valid modes are {MODES}.\n{CLI_HELP_MSG}")
|
|
|
|
-
|
|
|
|
- # Task
|
|
|
|
- task = overrides.pop("task", None)
|
|
|
|
- if task:
|
|
|
|
- if task == "classify" and mode == "track":
|
|
|
|
- raise ValueError(
|
|
|
|
- f"❌ Classification doesn't support 'mode=track'. Valid modes for classification are"
|
|
|
|
- f" {MODES - {'track'}}.\n{CLI_HELP_MSG}"
|
|
|
|
- )
|
|
|
|
- elif task not in TASKS:
|
|
|
|
- if task == "track":
|
|
|
|
- LOGGER.warning(
|
|
|
|
- "WARNING ⚠️ invalid 'task=track', setting 'task=detect' and 'mode=track'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}."
|
|
|
|
- )
|
|
|
|
- task, mode = "detect", "track"
|
|
|
|
- else:
|
|
|
|
- raise ValueError(f"Invalid 'task={task}'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}")
|
|
|
|
- if "model" not in overrides:
|
|
|
|
- overrides["model"] = TASK2MODEL[task]
|
|
|
|
-
|
|
|
|
- # Model
|
|
|
|
- model = overrides.pop("model", DEFAULT_CFG.model)
|
|
|
|
- if model is None:
|
|
|
|
- model = "yolo11n.pt"
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ 'model' argument is missing. Using default 'model={model}'.")
|
|
|
|
- overrides["model"] = model
|
|
|
|
- stem = Path(model).stem.lower()
|
|
|
|
- if "rtdetr" in stem: # guess architecture
|
|
|
|
- from ultralytics import RTDETR
|
|
|
|
-
|
|
|
|
- model = RTDETR(model) # no task argument
|
|
|
|
- elif "fastsam" in stem:
|
|
|
|
- from ultralytics import FastSAM
|
|
|
|
-
|
|
|
|
- model = FastSAM(model)
|
|
|
|
- elif "sam_" in stem or "sam2_" in stem or "sam2.1_" in stem:
|
|
|
|
- from ultralytics import SAM
|
|
|
|
-
|
|
|
|
- model = SAM(model)
|
|
|
|
- else:
|
|
|
|
- from ultralytics import YOLO
|
|
|
|
-
|
|
|
|
- model = YOLO(model, task=task)
|
|
|
|
- if isinstance(overrides.get("pretrained"), str):
|
|
|
|
- model.load(overrides["pretrained"])
|
|
|
|
-
|
|
|
|
- # Task Update
|
|
|
|
- if task != model.task:
|
|
|
|
- if task:
|
|
|
|
- LOGGER.warning(
|
|
|
|
- f"WARNING ⚠️ conflicting 'task={task}' passed with 'task={model.task}' model. "
|
|
|
|
- f"Ignoring 'task={task}' and updating to 'task={model.task}' to match model."
|
|
|
|
- )
|
|
|
|
- task = model.task
|
|
|
|
-
|
|
|
|
- # Mode
|
|
|
|
- if mode in {"predict", "track"} and "source" not in overrides:
|
|
|
|
- overrides["source"] = (
|
|
|
|
- "https://ultralytics.com/images/boats.jpg" if task == "obb" else DEFAULT_CFG.source or ASSETS
|
|
|
|
- )
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ 'source' argument is missing. Using default 'source={overrides['source']}'.")
|
|
|
|
- elif mode in {"train", "val"}:
|
|
|
|
- if "data" not in overrides and "resume" not in overrides:
|
|
|
|
- overrides["data"] = DEFAULT_CFG.data or TASK2DATA.get(task or DEFAULT_CFG.task, DEFAULT_CFG.data)
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ 'data' argument is missing. Using default 'data={overrides['data']}'.")
|
|
|
|
- elif mode == "export":
|
|
|
|
- if "format" not in overrides:
|
|
|
|
- overrides["format"] = DEFAULT_CFG.format or "torchscript"
|
|
|
|
- LOGGER.warning(f"WARNING ⚠️ 'format' argument is missing. Using default 'format={overrides['format']}'.")
|
|
|
|
-
|
|
|
|
- # Run command in python
|
|
|
|
- getattr(model, mode)(**overrides) # default args from model
|
|
|
|
-
|
|
|
|
- # Show help
|
|
|
|
- LOGGER.info(f"💡 Learn more at https://docs.ultralytics.com/modes/{mode}")
|
|
|
|
-
|
|
|
|
- # Recommend VS Code extension
|
|
|
|
- if IS_VSCODE and SETTINGS.get("vscode_msg", True):
|
|
|
|
- LOGGER.info(vscode_msg())
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-# Special modes --------------------------------------------------------------------------------------------------------
|
|
|
|
-def copy_default_cfg():
|
|
|
|
- """
|
|
|
|
- Copies the default configuration file and creates a new one with '_copy' appended to its name.
|
|
|
|
-
|
|
|
|
- This function duplicates the existing default configuration file (DEFAULT_CFG_PATH) and saves it
|
|
|
|
- with '_copy' appended to its name in the current working directory. It provides a convenient way
|
|
|
|
- to create a custom configuration file based on the default settings.
|
|
|
|
-
|
|
|
|
- Examples:
|
|
|
|
- >>> copy_default_cfg()
|
|
|
|
- # Output: default.yaml copied to /path/to/current/directory/default_copy.yaml
|
|
|
|
- # Example YOLO command with this new custom cfg:
|
|
|
|
- # yolo cfg='/path/to/current/directory/default_copy.yaml' imgsz=320 batch=8
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- - The new configuration file is created in the current working directory.
|
|
|
|
- - After copying, the function prints a message with the new file's location and an example
|
|
|
|
- YOLO command demonstrating how to use the new configuration file.
|
|
|
|
- - This function is useful for users who want to modify the default configuration without
|
|
|
|
- altering the original file.
|
|
|
|
- """
|
|
|
|
- new_file = Path.cwd() / DEFAULT_CFG_PATH.name.replace(".yaml", "_copy.yaml")
|
|
|
|
- shutil.copy2(DEFAULT_CFG_PATH, new_file)
|
|
|
|
- LOGGER.info(
|
|
|
|
- f"{DEFAULT_CFG_PATH} copied to {new_file}\n"
|
|
|
|
- f"Example YOLO command with this new custom cfg:\n yolo cfg='{new_file}' imgsz=320 batch=8"
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-if __name__ == "__main__":
|
|
|
|
- # Example: entrypoint(debug='yolo predict model=yolo11n.pt')
|
|
|
|
- entrypoint(debug="")
|
|
|