# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# 这是Ultralytics YOLO 的入口脚本,用于解析命令行参数并执行相应的任务(如训练、验证、预测、导出模型等)
import shutil #用于文件操作(如复制文件)
import subprocess #用于运行子进程(如调用 Streamlit)
import sys #用于访问命令行参数。
from pathlib import Path #提供路径操作的工具
from types import SimpleNamespace #用于创建简单的命名空间对象
from typing import Dict, List, Union
import cv2 #OpenCV 库,用于视频处理
from ultralytics.utils import (
ASSETS, #资源路径
DEFAULT_CFG, #默认配置
DEFAULT_CFG_DICT, #默认配置字典
DEFAULT_CFG_PATH, #默认配置文件路径
DEFAULT_SOL_DICT, #默认解决方案配置
IS_VSCODE, #是否在 VS Code 环境中运行
LOGGER, #日志记录器
# 它在多进程环境中用于区分不同的工作进程, 0表示主进程,负责日志记录、保存模型权重等任务, 其他进程(如 RANK=1, 2, 3 等)则负责并行计算和数据处理
# 当 RANK = -1 时,表示当前运行环境不涉及分布式训练,或者当前进程不参与分布式训练
RANK, # 用于分布式训练的变量,通常表示当前进程的排名(rank)。
ROOT, #项目根目录
RUNS_DIR, #运行结果保存目录
SETTINGS, #是一个用于管理用户配置的全局对象,是一个 SettingsManager 类的实例。它负责加载、保存和管理用户设置,这些设置存储在 settings.json 文件中
SETTINGS_FILE, # settings.json的路径: linux默认:/home/<用户名>/.config/Ultralytics
TESTS_RUNNING, # 用于指示代码是否处于测试运行状态,用于控制某些功能的启用或禁用
# IterableSimpleNamespace 是一个自定义类,它是 Python 标准库中的 SimpleNamespace 的扩展,添加了可迭代的功能。
# 这个类的主要作用是将配置字典转换为一个命名空间对象,使得配置参数可以通过点语法访问,同时支持迭代操作
IterableSimpleNamespace, #可迭代的命名空间类
__version__, #YOLO 的版本号
checks, #检查工具
colorstr, #用于彩色日志输出
deprecation_warn, #弃用警告
vscode_msg, #VS Code 扩展提示信息
yaml_load, #加载 YAML 文件
yaml_print, #打印 YAML 配置
)
# Define valid solutions
# 定义了 YOLO 支持的解决方案及其对应的类和方法, 这些类和方法在ultralytics/solutions文件夹中实现
# 例如,"count" 对应 ObjectCounter 类的 count 方法
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
# 定义了 YOLO 支持的模式(如训练,验证,预测,导出,跟踪,基准测试)
# 跟踪模式用于在视频流中跟踪目标物体
# 基准测试模式用于评估模型在不同导出格式下的性能
MODES = frozenset({"train", "val", "predict", "export", "track", "benchmark"})
# 定义了 YOLO 支持的任务(如检测,分割,分类,姿态估计,定向边界框)
# Pose(姿态估计) 是一种用于识别和定位物体关键点的任务
# OBB(Oriented Bounding Box,定向边界框) 是一种用于检测旋转物体的任务,输出的边界框可以是任意角度的矩形
TASKS = frozenset({"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 = frozenset({TASK2MODEL[task] for task in TASKS})
# ARGV: 获取命令行参数,如果没有参数,则默认为 ["", ""]
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
其中 SOLUTION(可选)是以下之一:{list(SOLUTION_MAP.keys())[:-1]}
ARGS(可选)是任意数量的 自定义`arg=value`对 ,例如 `show_in=True`,用于覆盖默认值
详细信息请参考:[配置](https://docs.ultralytics.com/usage/cfg)
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 => Streamlit 实时摄像头推理
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'
训练检测模型 10次,初始学习率为 0.01
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
在图像大小为 320 时,使用预训练的分割模型预测 YouTube 视频
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
在批量大小为 1、图像大小为 640 时,验证预先训练的检测模型
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
将 yolo11n 分类模型导出为ONNX 格式,图像大小为 224 x 128
(no TASK required)表示在执行命令时,任务类型可以通过模型文件名或上下文自动推断,因此用户不需要手动指定任务类型:detect segment classify pose obb
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
Ultralytics 解决方案用法
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 的要求。
yolo version 显示 YOLO 的版本信息。
yolo settings 显示或修改 YOLO 的用户设置
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 = frozenset(
{ # integer or float arguments, i.e. x=2 and x=2.0
"warmup_epochs",
"box",
"cls",
"dfl",
"degrees",
"shear",
"time",
"workspace",
"batch",
}
)
# 定义了值必须在 [0.0, 1.0] 范围内的浮点数配置键。
CFG_FRACTION_KEYS = frozenset(
{ # 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 = frozenset(
{ # integer-only arguments
"epochs",
"patience",
"workers",
"seed",
"close_mosaic",
"mask_ratio",
"max_det",
"vid_stride",
"line_width",
"nbs",
"save_period",
}
)
# 定义了必须是布尔值的配置键。
CFG_BOOL_KEYS = frozenset(
{ # 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",
}
)
# 将配置对象(可以是文件路径、字符串、字典或 SimpleNamespace 对象)转换为字典格式。
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)
# 特殊key, 由get_save_dir方法生成
if "save_dir" not in cfg:
overrides.pop("save_dir", None) # special override keys to ignore
check_dict_alignment(cfg, overrides)
# 利用字典解包合并字典, 如果 overrides 和 cfg 中有相同的键,则 overrides 中的值会覆盖 cfg 中的值。
cfg = {**cfg, **overrides} # merge cfg and overrides dicts (prefer overrides)
# 对 project 和 name 进行特殊处理,确保它们是字符串。
for k in "project", "name":
if k in cfg and isinstance(cfg[k], (int, float)):
cfg[k] = str(cfg[k])
# 如果 name 是 "model",则自动更新为模型文件名(去掉扩展名)。
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']}'.")
# 调用 check_cfg 对配置进行类型和值的检查
check_cfg(cfg)
# 返回一个 IterableSimpleNamespace 对象,方便后续使用。
return IterableSimpleNamespace(**cfg)
# 检查配置字典中的键值对是否符合类型和值的要求。是否满足浮点数类型,是否在[0.0,1.0]之间, 是否是布尔值等
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)
# 根据配置生成保存输出的目录路径
# 如果 args 中有 save_dir 属性,则直接返回该路径。
# 否则,根据 project、name 和 task 等配置生成默认路径。
# 使用 increment_path 确保路径唯一(如果已存在,则自动递增编号)。
# 返回最终的保存路径。
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)
# 处理已弃用的配置键,将其映射到当前的等效键,并发出弃用警告。
# 遍历 custom 字典的键。
# 如果发现已弃用的键(如 "boxes"、"hide_labels" 等),则将其替换为当前的等效键(如 "show_boxes"、"show_labels" 等)。
# 对于布尔值,自动处理字符串 "True" 和 "False" 的转换。
# 移除已弃用的键(如 "label_smoothing")。
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
# 检查自定义配置字典是否与基础配置字典对齐。
# 调用 _handle_deprecation 处理已弃用的键。
# 获取基础配置和自定义配置的键集合。
# 检查自定义配置中是否有不在基础配置中的键。
# 如果有不匹配的键,使用 difflib.get_close_matches 提供可能的相似键作为建议。
# 抛出 SyntaxError,并附带错误信息和帮助信息。
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 = (frozenset(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
# 功能:处理命令行参数列表,将被拆分的参数重新合并。
# 遍历参数列表 args,处理以下情况:
# 等号拆分:如果参数被拆分成 ['arg', '=', 'val'],则合并为 ['arg=val']。
# 等号后缀:如果参数为 ['arg=', 'val'],则合并为 ['arg=val']。
# 等号前缀:如果参数为 ['arg', '=val'],则合并为 ['arg=val']。
# 括号内的片段:如果参数包含括号(如 ['imgsz=[3,', '640,', '640]']),则将它们合并为一个完整的字符串 ['imgsz=[3,640,640]']。
# 返回处理后的参数列表。
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
# 处理与 Ultralytics HUB 相关的命令行命令,如登录和登出。
# 如果第一个参数是 "login",则尝试登录 HUB。如果提供了第二个参数(API 密钥),则使用该密钥登录。
# 如果第一个参数是 "logout",则从 HUB 登出。
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()
# 处理 YOLO 设置相关的命令行命令,如重置设置或更新特定设置。
# 如果第一个参数是 "reset",则删除设置文件并重置为默认设置。
# 如果提供了其他参数,则将它们解析为键值对,并更新设置。
# 检查更新后的设置是否与现有设置对齐。
# 打印当前设置,并提供帮助链接。
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.")
# 处理 YOLO 解决方案相关的命令行参数,并运行指定的计算机视觉解决方案流程。支持多种解决方案,如物体计数、对象模糊、实时推理等。
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.
"""
# 将默认解决方案配置(DEFAULT_SOL_DICT)和默认配置(DEFAULT_CFG_DICT)合并为一个字典。
full_args_dict = {**DEFAULT_SOL_DICT, **DEFAULT_CFG_DICT} # arguments dictionary
# overrides用于存储用户提供的覆盖参数。
overrides = {}
# check dictionary alignment
# 使用merge_equals_args处理参数,返回参数列表
# 解析每个参数:
# 如果参数包含等号(=),则调用parse_key_value_pair将其解析为键值对,并存储到overrides中。
# 如果参数是布尔值(如show),则直接设置为True。
# 如果参数格式错误或键不存在,则调用check_dict_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
# 获取解决方案名称
# 检查第一个参数是否是有效的解决方案名称。如果是,则提取并移除该参数。
if args and args[0] in SOLUTION_MAP:
if args[0] != "help":
s_n = args.pop(0) # Extract the solution name directly
# 如果第一个参数是help,则打印帮助信息。
else:
LOGGER.info(SOLUTIONS_HELP_MSG)
# 如果未提供有效解决方案名称,则默认使用count(物体计数)。
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
# 如果解决方案是inference,则检查是否安装了Streamlit(版本 >= 1.29.0)。
if s_n == "inference":
checks.check_requirements("streamlit>=1.29.0")
LOGGER.info("💡 Loading Ultralytics live inference app...")
# 使用subprocess.run启动Streamlit应用,运行实时推理
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] # 获取解决方案类和方法
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"]) # 打开视频文件
# 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) # 创建输出目录
# 初始化视频写入器
vw = cv2.VideoWriter(os.path.join(save_dir, "solution.avi"), cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
# 逐帧处理视频
try: # Process video frames
f_n = 0 # 帧编号
while cap.isOpened():
success, frame = cap.read()
if not success:
break
# 调用解决方案的处理方法(如count或process_queue)。
frame = process(frame, f_n := f_n + 1) if s_n == "analytics" else process(frame)
# 将处理后的帧写入输出视频。
vw.write(frame)
# 如果用户按下q,则中断处理
if cv2.waitKey(1) & 0xFF == ord("q"):
break
finally:
cap.release()
# 将形如 "key=value" 的字符串解析为键值对。
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.
"""
# 使用split("=", 1)按第一个等号分割字符串。
k, v = pair.split("=", 1) # split on first '=' sign
k, v = k.strip(), v.strip() # remove spaces
assert v, f"missing '{k}' value"
# 调用smart_value将值转换为合适的类型(如布尔值、整数、浮点数等)
return k, smart_value(v)
# 将字符串值转换为合适的 Python 类型。
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.
"""
# 支持将字符串转换为None、布尔值、整数、浮点数等。
v_lower = v.lower()
if v_lower == "none":
return None
elif v_lower == "true":
return True
elif v_lower == "false":
return False
else:
# 使用eval尝试评估字符串, 如果报错直接返回v. eval() 函数将字符串转换为相应的对象,并返回表达式的结果。
try:
return eval(v)
except Exception:
return v
# YOLO 的主入口函数,解析命令行参数并执行相应的任务(如训练、验证、预测等)。
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: # 如果未提供参数,则打印帮助信息并退出。
LOGGER.info(CLI_HELP_MSG)
return
# 定义特殊命令及其对应的处理函数。
# 例如,
# "help"打印帮助信息,
# "version"显示版本号,
# "settings"处理设置等。
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
# 为特殊命令添加别名,支持简写(如 -h、--help)。
# 添加单字符别名(如h对应help)。
# 添加复数形式的单数别名(如logins对应login)。
# 添加带前缀 - 和 -- 的别名。
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:
# 解析每个参数,支持键值对(如imgsz = 320)
k, v = parse_key_value_pair(a)
# 如果参数是cfg,则加载自定义配置文件
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)
# 如果参数是任务,则将其存储到overrides["task"]
elif a in TASKS:
overrides["task"] = a
# 如果参数是模式,则将其存储到overrides["mode"]
elif a in MODES:
overrides["mode"] = a
# 如果参数是特殊命令,则调用对应的处理函数并退出
elif a.lower() in special:
special[a.lower()]()
return
# 如果参数是布尔类型的默认配置项,则将其设置为True。
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
# 获取模式(如train、val、predic等)
# 如果未提供模式,则使用默认值(predict)
# 如果模式无效,则抛出错误。
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
# 获取任务(如detect、segment、classify等)
# 如果任务无效,则抛出错误。
# 如果未指定模型,则根据任务选择默认模型
task = overrides.pop("task", None)
if task:
if 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
# 加载模型,支持自定义模型文件
# 如果未指定模型,则使用默认模型(yolo11n.pt)
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() # stem 是 Path 对象的一个属性,表示文件名(不包含扩展名)
if "rtdetr" in stem: # guess architecture(推断模型架构) 如果模型文件名包含 rtdetr,则加载 RTDETR 类
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)
# 如果指定了预训练模型文件,则调用model.load方法加载
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
# 根据模式处理特定的参数。
# 逻辑:
# 如果模式是predict或track,且未指定source,则使用默认值。
# 如果模式是train或val,且未指定data或resume,则使用默认数据集。
# 如果模式是export,且未指定format,则使用默认格式(torchscript)。
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 获取模型的对应方法(如 train、val、predict),调用模型的对应方法,并传递用户提供的覆盖参数
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.
"""
# 将默认配置文件复制到当前目录,并命名为default_copy.yaml
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="")
# 命令格式
# YOLO 的命令行接口(CLI)使用以下语法:
# yolo TASK MODE ARGS
# TASK(可选):任务类型,可选值包括 [detect, segment, classify, pose, obb]。如果不明确指定,YOLO 将根据模型类型自动推断任务类型。
# MODE(必填):操作模式,可选值包括 [train, val, predict, export, track, benchmark]。
# ARGS(可选):自定义参数,如 imgsz=320,用于覆盖默认值。
# 支持的任务类型
# detect:目标检测,检测图像或视频中的物体并输出边界框和类别标签。
# segment:实例分割,检测物体并生成像素级掩码。
# classify:图像分类,对图像进行分类并输出类别标签。
# pose:姿态估计,检测图像中的人体关键点并输出位置。
# obb:旋转框检测,检测倾斜物体并输出旋转边界框。
# 支持的操作模式
# train:训练模型,使用指定数据集和配置文件训练 YOLO 模型。
# 示例:yolo detect train data=coco8.yaml model=yolo11n.pt epochs=100 imgsz=640
# val:验证模型,在验证集上评估模型性能。
# 示例:yolo detect val model=yolo11n.pt
# predict:推理预测,使用训练好的模型对新图像或视频进行推理。
# 示例:yolo detect predict model=yolo11n.pt source='image.jpg'
# export:导出模型,将模型导出为其他格式(如 ONNX、TensorRT)。
# 示例:yolo export model=yolo11n.pt format=onnx
# track:目标跟踪,在视频中跟踪物体的运动轨迹。
# 示例:yolo track model=yolo11n.pt source='video.mp4'
# benchmark:性能基准测试,测试模型在不同硬件上的推理速度。
# 示例:yolo benchmark model=yolo11n.pt imgsz=640
# 特殊命令
# YOLO 还支持一些特殊命令,用于查看帮助信息、版本号、设置等:
# yolo help:显示帮助信息。
# yolo checks:运行系统检查。
# yolo version:显示当前版本号。
# yolo settings:查看或修改设置。
# yolo copy-cfg:复制默认配置文件。
# yolo cfg:显示当前配置信息。
# 注意事项
# 参数必须以 arg=val 的形式传递,使用等号分隔,参数之间用空格分隔。
# 不要使用 -- 前缀或逗号 , 分隔参数。
(3) yolo11学习-cfg/__init__.py文件阅读
最新推荐文章于 2025-08-02 14:00:02 发布