YAML
YAML 是一种易于人类阅读的数据格式,使用缩进表示结构,广泛用于机器学习数据集和训练配置。介绍其语法、常见问题和替代方案。
YAML(“YAML 不是标记语言”的递归缩写)是一种人类可读的数据序列化语言,主要用于配置文件。它通过缩进而不是括号或标签描述嵌套数据,支持注释,并能直接映射为编程语言中的字典、列表、字符串和数字,因此同一个文件既便于人们编辑,也便于程序加载。在机器学习中,YAML 文件会在代码之外保存数据集路径、模型架构、超参数和流水线步骤,让实验易于复现、审查,也便于在 Git 中进行版本管理。当前规范为 YAML 1.2.2,YAML 1.2 的设计使有效 JSON 同时也是有效 YAML。
YAML 语法基础#
YAML 文档由三种节点构成。映射是 key: value 对,序列是以 - 开头的条目,或以内联形式写成 [a, b];标量则是字符串、数字和布尔值等单个值。嵌套结构通过空格缩进确定,不能使用制表符缩进。# 用于开始注释,--- 用于分隔同一文件中的多个文档,而锚点(&name)和别名(*name)则可在文件其他位置重用同一数据块。字符串通常无需引号,因此文件更简洁,但这也意味着解析器需要判断每个未加引号的值的类型。
机器学习工作流中的 YAML#
把设置保存在 YAML 中,可以将实验要做什么与代码如何实现分开:团队只需编辑文件,就能更换数据集或调整学习率,借助实验跟踪记录精确配置,并在拉取请求中审查更改。整个技术栈中的工具都使用 YAML,包括:Hydra 用于组合实验配置;GitHub Actions 用于持续集成流水线;Docker Compose 用于多容器应用;Kubernetes 清单用于部署模型。Ultralytics YOLO 在三个层级使用 YAML:数据集文件列出图像文件夹和类别名称;模型文件(如 yolo26.yaml)定义 YOLO26 的网络层和 n 到 x 的模型尺度配置;默认配置文件包含所有训练、预测和导出设置,这些设置可以由通过 cfg= 传入的自定义文件覆盖。这段摘录展示了随包提供的 coco8.yaml 数据集文件结构:
path: coco8 # dataset root dir
train: images/train # train images (relative to 'path')
val: images/val # val images (relative to 'path')
# Classes
names:
0: person
1: bicycle
2: car
# ... up to 79: toothbrush训练会按名称读取文件,根据 path 解析图像文件夹,并从 names 获取类别数量和名称:
from ultralytics import YOLO
# 加载预训练的 YOLO26 nano 模型
model = YOLO("yolo26n.pt")
# 在 YAML 文件所述的数据集上训练
results = model.train(data="coco8.yaml", epochs=3, imgsz=640)自定义数据集只需要自己的 YAML 文件,其中包含相同的键,指向图像并列出类别,格式遵循Ultralytics 检测数据集格式。
YAML、JSON 与 TOML 的比较#
- JSON:使用大括号、方括号和带引号的键,不支持注释,但在任何地方的解析方式都相同。它更适合程序间交换的数据,例如 API 响应和保存的预测结果,而不是供人编辑的文件。
- TOML:一种类似 INI 的格式,类型明确,缩进方面不易出错,由 Python 的
pyproject.toml使用。它处理深层嵌套数据时不太方便。 - XML:一种冗长的标签式标记语言,仍见于 Pascal VOC 等较旧的标注格式,但新配置文件很少采用。
常见的 YAML 陷阱#
大多数 YAML 错误都源自缩进:一个制表符或一个空格位置不一致,就会改变结构,或者导致解析器报出 ScannerError 或 ParserError。更隐蔽的问题来自隐式类型转换。大多数 Python 项目使用的解析器 PyYAML 遵循较旧的 YAML 1.1 规则,会将某些未加引号的单词转换为布尔值,并要求浮点数带小数点。使用 yaml.unsafe_load 或 PyYAML 的 UnsafeLoader 加载不可信文件,可能会构造任意 Python 对象并执行代码,因此配置代码会使用 yaml.safe_load,它只会创建普通数据类型:
import yaml
config = """
model: yolo26n.pt
epochs: 100
lr0: 1e-3
python: 3.10
country: NO
classes: [person, car]
"""
# safe_load builds plain Python dicts, lists, and scalars from the text
data = yaml.safe_load(config)
for key, value in data.items():
print(f"{key}: {value!r} ({type(value).__name__})")输出显示了三个意外情况:lr0 因为没有小数点而被加载为字符串 '1e-3';python: 3.10 会变成浮点数 3.1;国家代码 NO 则会变成布尔值 False,这是 YAML 1.1 中被戏称为“挪威问题”的规则。在 YAML 1.2 核心模式下,1e-3 会被加载为浮点数,NO 会保留为字符串,而 3.10 仍会变成 3.1。










