Configuration model#
This page explains how KonfAI turns a YAML file into live Python objects — the
reflection engine behind every Trainer, Predictor, and Evaluator. Read it
when a config key is not binding the way you expect, or before you expose a
custom class to YAML.
Note
Reading a config mutates it: loading a run resolves every default and
rewrites the YAML file in place, so the file on disk becomes the fully-resolved
record of the experiment. One consequence: a None value round-trips as the
literal string "None" — it is written back as "None" and reparsed to
None on the next read.
KonfAI is fundamentally a configuration-driven object builder.
The YAML file does not just pass values into a fixed script. It determines which Python classes are instantiated and how they are connected.
Root workflow objects#
The root key of the YAML selects the high-level workflow object:
Trainerfor trainingPredictorfor inferenceEvaluatorfor metrics
These names map directly to the public classes in:
konfai.trainer.Trainerkonfai.predictor.Predictorkonfai.evaluator.Evaluator
How YAML becomes Python objects#
This behavior is implemented by konfai.utils.config.Config, config(), and
apply_config().
In practice, the mapping is straightforward:
a class or function is optionally annotated with
@config("...")apply_config()inspects the constructor signatureYAML fields are matched against constructor parameter names
nested objects are recursively instantiated from nested mappings
This is why KonfAI configuration keys should generally:
use snake_case
match the actual Python constructor arguments
stay close to the shipped examples when you introduce a custom class
One important detail in the current codebase: @config() defaults to the class
name. For local custom classes, this usually adds an unnecessary extra subtree.
Without any decorator, a custom class UNetpp5 loaded through
classpath: Model:UNetpp5 reads its parameters directly from Trainer.Model.
Runtime environment variables#
Two environment variables drive configuration loading at runtime. Both are read
directly from os.environ by konfai.utils.config.Config:
Variable |
Meaning |
|---|---|
|
Path to the active YAML config file. |
|
Controls what happens when the config file or individual keys are missing. See Config modes below. |
The KonfAI CLI sets both variables for you from the --config argument. You only
need to set them by hand when you call configurable classes directly — for
example from a test or a notebook (see the testing notes in AGENTS.md).
The apply_config decorator and Config context manager#
Two cooperating pieces implement YAML → Python binding:
Config(key)is a context manager. On__enter__it loads the YAML file named byKONFAI_config_file, walks down the dot-separatedkeyto the matching subtree, and exposes it. On__exit__it merges the visited subtree back into the file, so a run that materializes defaults also records them in the YAML for reproducibility.apply_config("Root.Path")is a decorator placed on a configurable class or function. When the decorated object is called, it opens aConfigfor its subtree and binds arguments from the YAML before the callable runs.
A class additionally annotated with @config("Name") overrides the YAML key it
binds to; without it, the key defaults to the object’s own name.
How YAML keys map to arguments via reflection#
apply_config does not hard-code any field names. It inspects the target with
inspect.signature() and, for each parameter, reads a value from the active YAML
subtree using the parameter’s type annotation to decide how to convert it:
int,float,bool,str,torch.Tensor— cast directly from the YAML scalarLiteral[...]— validated against the allowed set (an invalid value raisesConfigError)pathlib.Path— wrapped as aPath; a non-existent path only logs a warninglist[...]/dict[str, ...]— parsed element-wisea nested configurable class — instantiated recursively by re-entering
apply_configon the nested subtree
Because the parameter names are the YAML keys, configuration keys should use
the exact constructor argument names (typically snake_case). A missing key
falls back to the parameter default, or to a default|... marker when one is
provided (see below).
Config modes#
KONFAI_CONFIG_MODE selects how KonfAI reacts to a missing file or missing keys:
Mode |
Behavior |
|---|---|
|
Normal run mode. The config file must already exist; values are read and the visited subtree is written back. A missing file raises |
|
Materialize defaults non-interactively. Missing files or keys are created from each field’s |
|
Like |
|
Skip config binding entirely. The decorated object is called with the arguments it was given, without reading the YAML — used when importing or constructing classes outside the config-driven flow. |
|
Delete the config file on context exit instead of writing it back — used for throwaway configs, for example in tests. |
An unset or unknown value behaves like Done. Tests that build configurable
objects directly must therefore set both variables explicitly.
classpath#
Many configurable components are selected dynamically through a classpath
string. The exact resolution logic is implemented by
konfai.utils.utils.get_module().
Typical examples:
Model:
classpath: segmentation.UNet.UNet
Model:
classpath: Model:UNetpp5
The two main styles are:
package.module.ClassName-style references resolved relative to a KonfAI namespacemodule:ClassNamereferences for explicit imports, often used for local files next to the YAML
Use the second form when you add custom files inside an example or project directory. It is usually the least ambiguous option.
default|... values#
The default|... prefix is an important KonfAI convention. Its behavior is
inferred directly from konfai.utils.config.Config._get_input_default().
It is used to express a fallback value that can still be overridden by config or interactive generation. Examples from the codebase include:
train_name: str = "default|TRAIN_01"classpath: str = "default|segmentation.UNet.UNet"default dictionary keys such as
default|Labels
In practice, you can read it as:
use the value after the pipe if nothing else is provided
Configuration is recursive#
Because nested constructors are instantiated recursively, the shape of the YAML mirrors the shape of the Python object graph. For example, a training config can nest:
TrainerModela chosen model class
optimizerschedulersoutputs_criterions
This is why KonfAI examples are such a good source of truth: they show real constructor trees that the framework accepts.
Practical mapping rules#
When a config does not behave as expected, check these rules first:
the YAML root must match the workflow you are launching
nested section names must match constructor parameters or any explicit
@config("...")keys you choselocal
classpathmodules must be importable from the current working directorythe YAML shape should mirror the Python object graph, not just the names you want conceptually
When to use local Python modules#
Use a local module when you need:
a custom model architecture
a custom transform
a project-specific helper that is not part of the built-in package
The examples/Synthesis workflow is the clearest repository example:
Model.pydefines local model classesUnNormalize.pydefines a local transformthe YAML references them with
Model:...andUnNormalize:...
Next steps#
Datasets and groups — how the configured dataset sections map onto lazy, patch-based storage.
Model graph and output naming — how
Modelsections address named module outputs for losses and metrics.Configuration reference — the key-by-key reference for the three workflow config files.