Skill v1.0.0
currentAutomated scan100/100version: "1.0.0" name: hydra description: Configuration framework for complex applications (Hydra). Dynamic hierarchical configuration by composition and override via CLI, YAML, and structured configs. Use for ML experiment management, multi-environment deployment, hyperparameter sweeps, and reproducible research workflows. Integrates with PyTorch Lightning, Weights & Biases, MLflow, and Optuna. license: MIT license tags: [experiment-configuration, config-composition, hyperparameter-sweeps, reproducible-runs, hydra] metadata: skill-author: K-Dense Inc.
Hydra
Overview
Hydra is a configuration framework that dynamically creates hierarchical configurations through composition and override. It eliminates hardcoded paths and config files scattered across projects. Use this skill for managing complex ML experiment configurations, multi-environment deployments, hyperparameter sweeps, and reproducible research workflows.
When to Use This Skill
This skill should be used when:
- Managing complex ML experiment configurations across models, datasets, and hardware
- Running hyperparameter sweeps with structured config overrides
- Switching between dev/staging/prod environments without code changes
- Setting up reproducible research with version-controlled configs
- Integrating configuration across PyTorch Lightning, W&B, and other ML tools
- Running multi-run experiments with different parameter combinations
- Organizing large ML codebases with clean separation of config from code
Core Capabilities
1. Installation
pip install hydra-core --upgrade
2. Basic Configuration Pattern
Directory structure:
conf/config.yamldb/mysql.yamlpostgresql.yamlmy_app.py
conf/config.yaml:
defaults:- db: mysql- _self_db:driver: mysqlhost: localhostport: 3306user: root
my_app.py:
import hydrafrom omegaconf import DictConfig, OmegaConf@hydra.main(version_base=None, config_path="conf", config_name="config")def my_app(cfg: DictConfig) -> None:print(OmegaConf.to_yaml(cfg))print(f"Connecting to {cfg.db.host}:{cfg.db.port}")if __name__ == "__main__":my_app()
CLI overrides:
python my_app.py # Uses mysqlpython my_app.py db=postgresql # Switch to postgresqlpython my_app.py db.host=prod-server # Override specific valuepython my_app.py db=postgresql db.port=5432 # Multiple overrides
3. Structured Configs (Python dataclasses)
from dataclasses import dataclass, fieldfrom typing import List, Optionalimport hydrafrom hydra.core.config_store import ConfigStore@dataclassclass ModelConfig:name: str = "resnet50"pretrained: bool = Truenum_classes: int = 1000@dataclassclass TrainingConfig:learning_rate: float = 0.001batch_size: int = 32max_epochs: int = 100optimizer: str = "adam"@dataclassclass DataConfig:dataset_path: str = "./data"num_workers: int = 4image_size: int = 224augmentations: List[str] = field(default_factory=lambda: ["flip", "rotate"])@dataclassclass ExperimentConfig:model: ModelConfig = ModelConfig()training: TrainingConfig = TrainingConfig()data: DataConfig = DataConfig()seed: int = 42experiment_name: str = "baseline"tags: List[str] = field(default_factory=list)# Register configcs = ConfigStore.instance()cs.store(name="base_config", node=ExperimentConfig)@hydra.main(version_base=None, config_path=None, config_name="base_config")def run_experiment(cfg: ExperimentConfig) -> None:print(f"Model: {cfg.model.name}")print(f"LR: {cfg.training.learning_rate}")print(f"Batch size: {cfg.training.batch_size}")if __name__ == "__main__":run_experiment()
CLI overrides with structured configs:
python experiment.py \model=resnet101 \training.learning_rate=0.0001 \training.batch_size=64 \data.image_size=256 \experiment_name=experiment_1
4. Config Groups (Modular Configs)
Directory:
conf/config.yamlmodel/resnet50.yamlvit_base.yamlefficientnet.yamloptimizer/adam.yamladamw.yamlsgd.yamldataset/imagenet.yamlcifar10.yaml
conf/config.yaml:
defaults:- model: resnet50- optimizer: adamw- dataset: imagenet- _self_training:epochs: 100mixed_precision: true
conf/model/vit_base.yaml:
name: vit_base_patch16_224pretrained: truenum_classes: 1000patch_size: 16hidden_dim: 768num_heads: 12num_layers: 12
Usage:
python train.py model=vit_base # Switch modelpython train.py model=efficientnet optimizer=sgd # Switch bothpython train.py model.vit_base.patch_size=32 # Nested override
5. Multi-Run (Hyperparameter Sweeps)
# Grid sweep: try all combinationspython train.py --multirun \training.learning_rate=0.001,0.0001,0.00001 \training.batch_size=32,64,128# Specific combinationspython train.py --multirun \model=resnet50,vit_base \optimizer=adamw,sgd# Range sweeppython train.py --multirun \seed=1,2,3,4,5# From a sweep configpython train.py --multirun --config-name=sweep_config
6. Output Management
Hydra automatically creates timestamped output directories:
outputs/2024-01-15/10-30-45/.hydra/ # Hydra config metadatatrain.log # Application logscheckpoints/ # Your artifacts
Access output directory in code:
import hydrafrom hydra.utils import get_original_cwd, to_absolute_path@hydra.main(...)def my_app(cfg):# Hydra changes working directory to output dirprint(os.getcwd()) # .../outputs/2024-01-15/10-30-45/print(get_original_cwd()) # Original working directory
7. PyTorch Lightning Integration
Config:
defaults:- model: resnet50- trainer: default- data: imagenet- _self_seed: 42
Training script:
@hydra.main(version_base=None, config_path="conf", config_name="config")def train(cfg: DictConfig):pl.seed_everything(cfg.seed)model = MyLightningModule(cfg.model)datamodule = MyDataModule(cfg.data)trainer = pl.Trainer(**cfg.trainer)trainer.fit(model, datamodule)
8. W&B / MLflow Logging Integration
@hydra.main(...)def train(cfg: DictConfig):# W&Bimport wandbwandb.init(project=cfg.wandb.project, config=OmegaConf.to_container(cfg))# MLflowimport mlflowmlflow.log_params(OmegaConf.to_container(cfg))
9. Instantiation (hydra.utils.instantiate)
# Config# model:# _target_: torch.optim.AdamW# lr: 0.001# weight_decay: 0.01from hydra.utils import instantiate@hydra.main(...)def train(cfg):optimizer = instantiate(cfg.optimizer) # Creates AdamW(lr=0.001, weight_decay=0.01)model = instantiate(cfg.model)scheduler = instantiate(cfg.scheduler, optimizer=optimizer)
Recursive instantiation:
model:_target_: mylib.models.ResNetClassifierbackbone:_target_: torchvision.models.resnet50pretrained: truenum_classes: 1000
10. Resolvers (Dynamic Value Resolution)
# Register a custom resolverfrom omegaconf import OmegaConfOmegaConf.register_new_resolver("sum", lambda x, y: x + y)OmegaConf.register_new_resolver("eval", eval)# Use in YAML# total_steps: ${sum:${train.epochs},${train.warmup_epochs}}# batch_size_gb: ${eval:'int(${batch_size} * ${image_size}**2 * 3 * 4 / 1e9)'}
Built-in resolvers:
output_dir: ${hydra:runtime.output_dir}now: ${now:%Y-%m-%d_%H-%M-%S}# Path relative to config filedata_path: ${oc.env:DATA_PATH,/default/path}
Key Patterns
- Separate config from code — all tunable params go in YAML/dataclasses
- Use config groups for model/dataset/optimizer families — modular swapping
- CLI overrides are the source of truth — YAML provides defaults, CLI finalizes
- Use `instantiate()` for object creation from config — reduces boilerplate
- Timestamped output dirs are automatic — no need to manage manually
- Multi-run for sweeps —
--multirunplus comma-separated values - Check in config files — they ARE your experiment documentation
References
- Hydra Documentation
- Structured Configs Tutorial
- OmegaConf Documentation
- lightning-hydra-template — full ML template
- hydra-zen — Pythonic Hydra utilities