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

214 lines
4.9 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 里注册了两个命令:
```toml
[project.scripts]
yolo = "ultralytics.cfg:entrypoint"
ultralytics = "ultralytics.cfg:entrypoint"
```
因此终端里的 `yolo ...` 最终会调用:
```python
ultralytics.cfg.entrypoint()
```
## 2. `entrypoint()` 收集原始参数
`entrypoint(debug: str = "")` 的第一步是:
```python
args = (debug.split(" ") if debug else ARGV)[1:]
```
也就是去掉命令名本身,保留后面的参数,例如:
```text
yolo detect train model=yolo26n.pt data=coco8.yaml epochs=100
```
会被看成:
```python
["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`
例如:
```text
yolo detect train model=yolo26n.pt data=coco8.yaml epochs=100
```
会被解析成近似:
```python
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 做分派:
```python
stem = Path(model).stem.lower()
```
当前分支逻辑是:
- stem 含 `rtdetr``RTDETR(model)`
- stem 含 `fastsam``FastSAM(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. 真正执行
最后一步就是:
```python
getattr(model, mode)(**overrides)
```
例如 `mode="train"` 时,等价于:
```python
model.train(**overrides)
```
如果当前是普通 YOLO 检测模型,这会继续进入:
1. `YOLO.train()`
2. 实例化对应 trainer
3. `trainer.train()`
## Example
命令:
```bash
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 里展开的。