Files
yolov26_3d/docs/yolo_command_flow.md
2026-06-24 09:35:46 +08:00

4.9 KiB
Executable File
Raw Blame History

How the yolo Command Works

Overview

本文描述当前仓库里 yolo ... CLI 的真实入口流程,重点解释:

  • console script 是如何注册的
  • entrypoint() 如何解析参数
  • task / mode / model 如何决定最终执行哪个类和哪个方法

主要代码位置:

  • pyproject.toml
  • ultralytics/cfg/__init__.py
  • ultralytics/engine/model.py
  • ultralytics/models/yolo/model.py

1. Console Script 注册

pyproject.toml 里注册了两个命令:

[project.scripts]
yolo = "ultralytics.cfg:entrypoint"
ultralytics = "ultralytics.cfg:entrypoint"

因此终端里的 yolo ... 最终会调用:

ultralytics.cfg.entrypoint()

2. entrypoint() 收集原始参数

entrypoint(debug: str = "") 的第一步是:

args = (debug.split(" ") if debug else ARGV)[1:]

也就是去掉命令名本身,保留后面的参数,例如:

yolo detect train model=yolo26n.pt data=coco8.yaml epochs=100

会被看成:

["detect", "train", "model=yolo26n.pt", "data=coco8.yaml", "epochs=100"]

如果用户没有传任何参数CLI 会直接打印帮助信息并返回。

3. 特殊命令优先处理

当前代码里的特殊命令包括:

  • help
  • checks
  • version
  • settings
  • cfg
  • hub
  • login
  • logout
  • copy-cfg
  • solutions

这些命令在参数循环里一旦命中,就会立刻执行并 return,不会再走模型实例化。

4. 常规参数解析

entrypoint() 逐个处理参数,核心规则是:

  1. merge_equals_args(args) 先把 arg = value 这种带空格写法并回去
  2. --foo 会被警告后改写成 foo
  3. 若参数里有 =,走 parse_key_value_pair()
  4. 若参数等于某个 task写入 overrides["task"]
  5. 若参数等于某个 mode写入 overrides["mode"]
  6. 若参数是布尔型默认配置键,则自动设为 True

例如:

yolo detect train model=yolo26n.pt data=coco8.yaml epochs=100

会被解析成近似:

overrides = {
    "task": "detect",
    "mode": "train",
    "model": "yolo26n.pt",
    "data": "coco8.yaml",
    "epochs": 100,
}

5. mode 校验

解析完成后会先确定 mode

  • 若没传,则回退到 DEFAULT_CFG.mode,否则默认 predict
  • 若传了非法值,直接报错

当前合法 mode 包括:

  • train
  • val
  • predict
  • export
  • track
  • benchmark

6. task 校验

然后处理 task

  • 若传了 task就检查是否合法
  • 若没传但给了模型,后面会从模型侧再推断
  • 若传了 task 但没传 model会根据 TASK2MODEL 自动补默认模型

当前合法 task 包括:

  • detect
  • segment
  • classify
  • pose
  • obb

7. 模型实例化分派

接下来 entrypoint() 会取出 model,根据文件名 stem 做分派:

stem = Path(model).stem.lower()

当前分支逻辑是:

  • stem 含 rtdetrRTDETR(model)
  • stem 含 fastsamFastSAM(model)
  • stem 含 sam_ / sam2_ / sam2.1_SAM(model)
  • 否则 → YOLO(model, task=task)

所以这里不是简单的“文件名里含 sam 就走 SAM”而是更窄的前缀判断。

8. task 与 model 冲突时的处理

模型实例化后CLI 还会做一次 task 对齐:

  • 如果用户显式传的 task 和模型自身 model.task 冲突
  • 则忽略用户传入的 task
  • 以模型解析出来的 task 为准

这是为了避免类似“拿分类模型跑 detect task”这种冲突配置继续往后传播。

9. mode 相关默认参数补全

在真正执行前CLI 还会按 mode 补一些默认参数:

  • predict/track 且没传 source:自动补默认图像
  • train/val 且没传 data 且不是 resume:自动补默认数据集
  • export 且没传 format:自动补 torchscript

10. 真正执行

最后一步就是:

getattr(model, mode)(**overrides)

例如 mode="train" 时,等价于:

model.train(**overrides)

如果当前是普通 YOLO 检测模型,这会继续进入:

  1. YOLO.train()
  2. 实例化对应 trainer
  3. trainer.train()

Example

命令:

yolo detect train model=yolo26n.pt data=coco8.yaml epochs=100 lr0=0.01

主流程可以概括成:

  1. yolo 命令调用 ultralytics.cfg.entrypoint()
  2. 解析得到 task=detect, mode=train, model=yolo26n.pt, ...
  3. 根据 model 实例化 YOLO("yolo26n.pt", task="detect")
  4. 执行 model.train(data="coco8.yaml", epochs=100, lr0=0.01, ...)
  5. YOLO.train() 再去构建对应 trainer 并开始训练

一句话总结

yolo ... CLI 的本质是:

  • 先在 entrypoint() 里把命令行翻译成 overrides
  • 再根据 model 选择合适的 model class
  • 最后通过 getattr(model, mode)(**overrides) 分发到 train/val/predict/export/...

它本身不关心 Ground3D、ROI 或 virtual-camera 这些任务细节;那些差异是在具体 trainer / dataset / loss 里展开的。