YAML
YAML is a human-readable data format that uses indentation for structure, widely used for ML dataset and training configs. Syntax, pitfalls, alternatives.
YAML (a recursive acronym for "YAML Ain't Markup Language") is a human-readable data serialization language used mostly for configuration files. It describes nested data with indentation instead of brackets or tags, supports comments, and maps directly onto the dictionaries, lists, strings, and numbers of programming languages, so the same file is easy for people to edit and for programs to load. In machine learning, YAML files hold dataset paths, model architectures, hyperparameters, and pipeline steps outside the code, which makes experiments easy to reproduce, review, and version in Git. The current specification is YAML 1.2.2, and YAML 1.2 was designed so that valid JSON is also valid YAML.
YAML Syntax Basics#
A YAML document is built from three kinds of nodes. Mappings are key: value pairs, sequences are items that start with - or are written inline as [a, b], and scalars are single values such as strings, numbers, and booleans. Nesting is set by indentation with spaces, and tab characters are not allowed for indentation. A # starts a comment, --- separates several documents in one file, and anchors (&name) with aliases (*name) let one block be reused elsewhere in the file. Strings usually need no quotes, which keeps files short but means the parser decides each unquoted value's type.
YAML in Machine Learning Workflows#
Keeping settings in YAML separates what an experiment does from how the code does it: a team can swap datasets or change learning rates by editing a file, record the exact configuration with experiment tracking, and review changes in pull requests. Tools across the stack use it, including Hydra for composing experiment configs, GitHub Actions for continuous integration pipelines, Docker Compose for multi-container apps, and Kubernetes manifests for deploying models. Ultralytics YOLO uses YAML at three levels: dataset files list image folders and class names, model files such as yolo26.yaml define the layers and the n to x scales of YOLO26, and a default configuration file holds every training, prediction, and export setting, which a custom file passed with cfg= can override. This excerpt shows the structure of the bundled coco8.yaml dataset file:
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: toothbrushTraining reads the file by name, resolves the image folders from path, and takes the class count and names from names:
from ultralytics import YOLO
# Load a pretrained YOLO26 nano model
model = YOLO("yolo26n.pt")
# Train on the dataset described by the YAML file
results = model.train(data="coco8.yaml", epochs=3, imgsz=640)A custom dataset needs only its own YAML file with the same keys, pointing to its images and listing its classes in the Ultralytics detection dataset format.
YAML vs. JSON vs. TOML#
- JSON: Uses braces, brackets, and quoted keys, has no comments, and parses the same everywhere. It suits data exchanged between programs, such as API responses and saved predictions, more than files people edit.
- TOML: An INI-like format with explicit types and fewer indentation surprises, used by Python's
pyproject.toml. It is less convenient for deeply nested data. - XML: A verbose tag-based markup language still found in older annotation formats such as Pascal VOC, rarely chosen for new configuration files.
Common YAML Pitfalls#
Most YAML errors come from indentation: a tab character or one misaligned space changes the structure or stops the parser with a ScannerError or ParserError. The subtler problems come from implicit typing. PyYAML, the parser most Python projects use, follows the older YAML 1.1 rules, which turn some unquoted words into booleans and require a decimal point in floats. Loading untrusted files with yaml.unsafe_load or PyYAML's UnsafeLoader can construct arbitrary Python objects and run code, so configuration code uses yaml.safe_load, which builds only plain data types:
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__})")The output shows three surprises: lr0 loads as the string '1e-3' because it lacks a decimal point, python: 3.10 becomes the float 3.1, and the country code NO becomes the boolean False, a YAML 1.1 rule nicknamed the Norway problem. Under the YAML 1.2 core schema, 1e-3 loads as a float and NO stays a string, while 3.10 still becomes 3.1.










