Declarative YAML model graphs#
This page documents the YAML model builder — how to describe a complete
network as a .yml file instead of a Python class. Read it when you want a
model that lives entirely in configuration, with the same named outputs and
routing as code-defined models.
konfai.utils.model_builder builds a full konfai.network.network.Network.
Every YAML entry is installed through ModuleArgsDict.add_module, so YAML
models support the same named outputs, branch routing, aliases, checkpoint
metadata, optimizer configuration, and loss attachment as Python models.
The segmentation example is defined in examples/Segmentation/UNet.yml; its
training and prediction configs load it with classpath: UNet.yml. The older
Python konfai.models.python.segmentation.UNet remains available for compatibility.
Document structure#
name: RoutedHead
parameters:
dim: 2
in_channels: 16
classes: 3
network:
dim: ${dim}
in_channels: ${in_channels}
modules:
- name: Conv
type: Conv
args:
dim: ${dim}
in_channels: ${in_channels}
out_channels: ${classes}
kernel_size: 1
- name: Softmax
type: Softmax
args: {dim: 1}
- name: Argmax
type: ArgMax
args: {dim: 1}
build_model_from_yaml(yaml_path="model.yml") returns a YamlNetwork, not a
torch.nn.Sequential. ModelLoader also accepts .yml and .yaml paths.
Relative paths are resolved next to the active KONFAI_config_file — the
model .yml is looked up relative to the config file that references it, not
the current working directory.
Routing and nested graphs#
Module entries accept the routing fields from add_module:
in_branchandout_branchaliaspretrainedrequires_gradtraining
A nested modules list creates a ModuleArgsDict subgraph:
modules:
- name: Encoder
modules:
- name: Conv
type: Conv2d
args: {in_channels: 1, out_channels: 8, kernel_size: 3, padding: 1}
- name: Preserve
type: Identity
out_branch: [1]
- name: Join
type: Concat
in_branch: [0, 1]
Module paths remain stable (Encoder:Conv, Join, and so on) for
outputs_criterions and outputs_dataset.
Parameters and safe objects#
An exact ${path} value references parameters; list indices use dotted
numbers such as ${channels.2}. Runtime configuration can override the entire
parameters mapping under the model section.
Some KonfAI blocks need configuration objects. They are constructed through a separate safe object registry:
parameters:
block_configs:
- $object: BlockConfig
args:
kernel_size: 3
padding: 1
activation: ReLU
norm_mode: NONE
modules:
- name: Block
type: ConvBlock
args:
in_channels: 1
out_channels: 32
dim: 2
block_configs: ${block_configs}
$multiply provides safe numeric multiplication for derived channel counts.
No YAML value is passed to eval or used as an import path.
Registry#
Built-ins, grouped:
Dimension-aware factories (pick the 1-D/2-D/3-D variant from
dim):Conv,ConvTranspose,MaxPool,AvgPool,AdaptiveAvgPool,BatchNorm,InstanceNorm; explicitConv1d/Conv2d/Conv3dandDropout/Dropout1d/2d/3d.Normalization / regularization:
GroupNorm,LayerNorm,Dropout.Activations:
ReLU,LeakyReLU,PReLU,GELU,Sigmoid,Tanh,Softmax.Linear / shape:
Linear,Flatten,Upsample,Identity,Permute,View,Select,Unsqueeze,ArgMax.Routing leaves:
Concat,Add,Multiply.Composite blocks:
ConvBlock,ResBlock,Attention.Transformer:
MultiHeadSelfAttention,PositionalEmbedding(withLayerNorm,Linear,GELU) — enough to express a ViT encoder.
Call list_registered_modules() for the authoritative, up-to-date list. Applications
may add a trusted torch.nn.Module subclass with register_module(name, cls).
Duplicate names and non-module classes raise ConfigError.
Shipped model catalog#
konfai/models/ is split by form: python/ holds the builtin Python model classes
(referenced as classpath: segmentation.UNet.UNet), yaml/ the declarative catalog.
KonfAI ships a catalog of common medical-imaging architectures as declarative YAML
under konfai/models/yaml/. Reference one from any config with a default| marker —
the declarative counterpart of a Python model classpath:
Model:
classpath: default|AttentionUNet.yml
Every catalog entry is built from the curated registry (no code execution) and is locked by a test at the strongest available level — weight-exact graph equivalence against a reference implementation where one exists, otherwise a structural check (builds, forward on 2-D and 3-D inputs, correct output shape, deep-supervision heads) with any divergence from the reference documented in the file header:
Entry |
Validation |
Loads pretrained from |
|---|---|---|
|
weight-exact vs their KonfAI Python classes |
KonfAI checkpoints |
|
weight-exact vs MONAI |
MONAI checkpoints (via the bridge) |
|
weight-exact vs torchvision ResNet-18 |
torchvision ImageNet (via the bridge) |
|
weight-exact vs nnU-Net |
nnU-Net / TotalSegmentator / MRSeg checkpoints (via the bridge) |
|
weight-exact vs torchvision (all 5 feature maps exact) |
torchvision ImageNet (via the bridge) |
|
structural + encoder token-features allclose vs MONAI |
— (encoder maths verified) |
|
structural-strict (graph differs from MONAI, documented) |
— |
|
weight-exact vs nnU-Net |
nnU-Net ResEnc / ImpactSeg checkpoints (via the bridge) |
|
weight-exact vs |
smp / ImpactSynth checkpoints (via the bridge) |
PlainConvUNet, ResidualEncoderUNet and UNetPlusPlus are parametric models
(konfai/models/python/segmentation/): rather than a fixed-topology .yml, you reference
the class and declare the architecture inline, so one model covers any depth / width / class
count — e.g.
Model:
classpath: segmentation.residualencoderunet.ResidualEncoderUNet
ResidualEncoderUNet:
dim: 2
in_channels: 5
n_stages: 6
features_per_stage: [24, 48, 96, 192, 256, 256]
strides: [1, 2, 2, 2, 2, 2]
n_blocks_per_stage: [1, 2, 2, 3, 3, 3]
num_classes: 12
deep_supervision: false
VGG16 is the feature-extractor entry: it exposes five named multi-layer outputs
(Block_0:Out … Block_4:Out, channels 64/128/256/512/512 — the torchvision
features slices [0:4]/[4:9]/[9:16]/[16:23]/[23:30]) so a perceptual / feature /
IMPACT-style loss can be attached to any of them through outputs_criterions.
The MCP server lists the catalog via list_components(kind="model") alongside the
Python model classes.
Which form should I use?#
There are three ways to put a common architecture into a KonfAI config, and they are not redundant — pick by what you need:
You want to… |
Use |
Why |
|---|---|---|
Train/run the vanilla model as-is, one output, one loss |
|
KonfAI wraps any |
Supervise internal layers (deep supervision, feature/perceptual losses), edit the architecture without code, or share it safely |
`classpath: default |
SegResNet.yml` |
Do the above and start from someone’s pretrained weights |
`default |
An imported nn.Module is a black box: only its final output is visible to KonfAI’s
loss/evaluation machinery. The YAML form is what unlocks per-node supervision — that is
the reason to rebuild an architecture rather than import it.
Loading pretrained weights#
A catalog entry that is weight-exact to a reference (e.g. SegResNet.yml ↔ MONAI
SegResNet) can be loaded from that reference’s checkpoint even though the two use
different module names, via konfai.utils.pretrained.transfer_weights_by_execution_order.
It pairs the two graphs’ weighted leaves in forward-execution order and copies them with
a shape check, so no hand-written key map is needed:
from monai.networks.nets import SegResNet
from konfai.utils.model_builder import build_model_from_yaml
from konfai.utils.pretrained import transfer_weights_by_execution_order
reference = SegResNet(spatial_dims=3, init_filters=8, in_channels=1, out_channels=2,
blocks_down=(1, 2, 2, 4), blocks_up=(1, 1, 1))
reference.load_state_dict(torch.load("segresnet_pretrained.pt")) # your trained checkpoint
net = build_model_from_yaml(yaml_path="konfai/models/yaml/SegResNet.yml",
parameters={"dim": 3, "upsample_mode": "trilinear", "nb_class": 2})
example = torch.randn(1, 1, 16, 16, 16)
transfer_weights_by_execution_order(
target=net, source=reference,
target_forward=lambda: list(net.named_forward(example)),
source_forward=lambda: reference(example),
)
The transfer is strict: if the two graphs are not weight-exact (different leaf count or a
mismatched shape) it raises ConfigError rather than silently mis-loading a network.
Configuration example#
Trainer:
Model:
classpath: UNet.yml
UNet:
parameters:
dim: 2
channels: [1, 32, 64, 128, 256]
nb_class: 41
optimizer:
name: AdamW
lr: 0.001
outputs_criterions:
UNetBlock_0:Head:Conv:
targets_criterions: {}
See examples/Segmentation/UNet.yml for a complete routed encoder/decoder with
skip connections and nested heads.
Next steps#
Model graph and output naming — how named module paths are addressed by
outputs_criterionsandoutputs_dataset.Segmentation Example — a complete training run driven by
UNet.yml.