Configuration System¶
VersatIL uses Hydra and OmegaConf for experiment configuration. This combination provides hierarchical composition of reusable config blocks, typed validation via Python dataclasses, and CLI overrides without code changes.
Hydra Composition Pattern¶
Instead of monolithic config files, VersatIL composes small, reusable config blocks stored in src/versatil/hydra_configs/. An end-to-end training config declares which blocks to combine via defaults::
# src/versatil/hydra_configs/end_to_end_training_runs/bowel_retraction/act.yaml
# Required in all end-to-end configs: declares the package scope and the target dataclass.
# @package _global_
_target_: versatil.configs.main.MainConfig
defaults:
- /task: base
- /policy: base
- /experiment: default
- /task/dataset_schema: bowel_retraction_v2
- /task/dataloader: bowel_retraction
- /task/action_space: deltas_cf_pos_gripper_phase
- /task/observation_space: stereo_rgb
- /training: default
- /policy/encoding_pipeline: stereo_rgb
- /policy/decoder: act_default
- /policy/algorithm: bc_with_vae_gaussian
- /policy/loss: regression_gripper_kl
- _self_
Each line references a YAML file under src/versatil/hydra_configs/. For example, /policy/algorithm: bc_with_vae_gaussian loads src/versatil/hydra_configs/policy/algorithm/bc_with_vae_gaussian.yaml.
The _self_ entry at the end means that any values defined directly in this file override values from the defaults.
Config Group Hierarchy¶
src/versatil/hydra_configs/
├── end_to_end_training_runs/ # Complete training configs
│ ├── bowel_retraction/
│ ├── libero_hdf5/
│ └── ...
├── experiment/ # Experiment settings
├── training/ # Training hyperparameters
├── task/ # Task definitions
│ ├── action_space/
│ ├── observation_space/
│ ├── dataloader/
│ └── dataset_schema/
├── policy/ # Policy components
│ ├── encoding_pipeline/ # Encoder configs
│ ├── decoder/ # Architecture configs
│ ├── algorithm/ # Algorithm configs
│ └── loss/ # Loss configs
└── end_to_end_deploy/ # Deployment endpoint configs
Creating a New Experiment¶
To create a new experiment, write a YAML file that references existing config blocks and overrides only the parameters that differ:
# src/versatil/hydra_configs/end_to_end_training_runs/my_dataset/diffusion.yaml
defaults:
- /task: base
- /policy: base
- /experiment: default
- /task/dataset_schema: my_dataset
- /task/dataloader: my_dataset
- /task/action_space: my_action_space
- /task/observation_space: stereo_rgb
- /training: default
- /policy/encoding_pipeline: stereo_rgb
- /policy/decoder: dit_block_transformer
- /policy/algorithm: diffusion
- /policy/loss: regression_gripper
- _self_
experiment:
checkpoint_folder: ${checkpoint_dir:my_dataset}
task:
observation_horizon: 2
prediction_horizon: 16
No need to redefine encoder architectures, optimizer settings, or other parameters that stay at their defaults.
OmegaConf Typed Dataclasses¶
Every config file maps to a Python dataclass defined in src/versatil/configs/. This provides type safety: if a YAML value has the wrong type or a required field is missing, the run fails immediately at startup.
MainConfig Structure¶
The root config composes all top-level sections:
@dataclass
class MainConfig:
experiment: ExperimentConfig
task: TaskSpaceConfig
training: TrainingConfig
policy: PolicyConfig
quantization: Any = None
Example: PolicyConfig¶
@dataclass
class PolicyConfig:
_target_: str = "versatil.models.policy.Policy"
encoding_pipeline: EncodingPipelineConfig = MISSING
algorithm: Any = MISSING
decoder: Any = MISSING
observation_space: ObservationSpaceConfig = "${task.observation_space}"
action_space: ActionSpaceConfig = "${task.action_space}"
prediction_horizon: int = "${task.prediction_horizon}"
observation_horizon: int = "${task.observation_horizon}"
device: str = "${experiment.device}"
loss: CompositeLossConfig = MISSING
- Fields set to
MISSINGare required and must be provided by a config file or CLI override. - Fields with defaults are optional and filled automatically during config merging.
- Fields using
${...}interpolation reference values from other config sections.
Adding a New Config¶
When adding a new component:
-
Define a
dataclassinsrc/versatil/configs/: -
Register it in the ConfigStore (in the matching domain module under
src/versatil/configs/store/, e.g.policy.py): -
Create the YAML file in
src/versatil/hydra_configs/:
The ConfigStore validates that YAML values match the dataclass types at startup.
Interpolation¶
OmegaConf interpolation allows referencing values from other parts of the config tree using ${} syntax. This keeps configs DRY and prevents inconsistencies.
Cross-References¶
policy:
prediction_horizon: ${task.prediction_horizon}
observation_space: ${task.observation_space}
device: ${experiment.device}
Changing task.prediction_horizon automatically propagates to every field that references it.
Custom Resolvers¶
VersatIL registers custom resolvers in src/versatil/configs/__init__.py for accessing enum values and environment variables in YAML:
# Enum resolvers — access Python Enum.value from YAML
input_keys: ${cameras:LEFT} # Resolves to Cameras.LEFT.value ("left")
backbone: ${rgb_backbone:RESNET18} # Resolves to RGBBackboneType.RESNET18.value
activation: ${activation_function:GELU} # Resolves to ActivationFunction.GELU.value
# Path resolvers — read from environment variables
checkpoint_folder: ${checkpoint_dir:bowel_retraction} # VERSATIL_CHECKPOINT_DIR/bowel_retraction
zarr_path: ${zarr_dir:my_dataset} # VERSATIL_ZARR_DIR/my_dataset
cache: ${cache_dir:} # VERSATIL_CACHE_DIR
# Dataset directory resolver: takes the environment variable to read as its
# first argument and an optional subpath as the second
dataset_folders: ${dataset_dir:VERSATIL_LIBERO_HDF5_DIR,libero_10} # $VERSATIL_LIBERO_HDF5_DIR/libero_10
# Environment variable resolver
api_key: ${env:WANDB_API_KEY} # Direct env var access
Available enum resolvers are available at src/versatil/configs/__init__.py.
Config Validation¶
VersatIL validates configurations at multiple levels to catch errors before training begins.
Type Validation (OmegaConf)¶
Typed dataclasses catch type mismatches and missing fields at config load time:
Feature Validation (ExperimentValidator)¶
The ExperimentValidator in src/versatil/validation.py validates that encoder outputs match decoder input requirements during model construction:
# src/versatil/validation.py
def validate_decoder_encoder_compatibility(self):
available_features = self.encoding_pipeline.get_features()
self.decoder.decoder_input.validate_feature_types(
available_features=available_features
)
This is simplified -- the full method also validates individual feature keys. It catches feature name mismatches (e.g., decoder expects "fused_visual" but no fusion produces it) and feature type mismatches (e.g., decoder expects FLAT features but receives SPATIAL) before any data is loaded.
Loss Key Validation¶
When experiment.validate_loss_keys=true (default), the experiment validates that all loss module keys correspond to valid action space keys, preventing silent misconfiguration of loss components.
CLI Usage¶
Override Values¶
python -m versatil.endpoints.train \
--config-name end_to_end_training_runs/bowel_retraction/act \
training.optimizer.lr=1e-4 \
task.dataloader.batch_size=64 \
training.num_epochs=200
Swap Config Groups¶
Replace an entire config group from the command line:
python -m versatil.endpoints.train \
--config-name end_to_end_training_runs/bowel_retraction/act \
policy/loss=regression_gripper_mmd \
policy/algorithm=diffusion
View Resolved Config¶
Use Hydra's --cfg flag to inspect the final merged config without running training: