How to configure morel
morel's configuration is a tree of frozen dataclasses. You build it
once from a YAML file or programmatically, then pass the result to
Pipeline, Experiment, or the CLI.
The configuration tree at a glance
Config
├── seed global RNG seed
├── device "cpu" | "cuda" | "auto"
├── data raw/processed paths, category, k-core min
├── encoder text + visual model names
├── masking kind, ratio, per-mask seed
├── retrieve strategy (mage, anchor, bfs, acs, none)
├── encode joint encoder (kind, hidden, layers, heads, dropout, pe)
├── route router (kind, p, tau)
├── codebook VQ / Gumbel-VQ (kind, size)
├── complete modality completer (kind, hidden)
├── recommend downstream ranker (kind, embed, layers)
├── completion completion training loop (epochs, batch, lr, ...)
├── recommendation recommendation training loop (epochs, batch, ...)
├── eval ks, robustness sweep, ablation condition names
├── serve host/port/workers
└── log level, structured flag, output directory
Every section is validated at construction time, so a field out of
range (masking.ratio = 2.0) raises Cfg immediately rather than
producing silently broken state.
Build a config
From a YAML file
configs/synthetic.yaml:
seed: 42
device: cpu
data:
raw: data/raw
processed: data/processed
category: Beauty
min: 5
encoder:
text: sentence-transformers/all-MiniLM-L6-v2
visual: resnet50
td: 384
visual_dim: 2048
masking:
kind: bernoulli
ratio: 0.4
retrieve:
kind: mage
anchors: 10
iters: 10
encode:
kind: transformer
hidden: 128
layers: 2
heads: 4
dropout: 0.5
pe: 20
route:
kind: top
p: 4
tau: 0.5
codebook:
kind: gumbel
size: 100
complete:
kind: mlp
hidden: 128
recommend:
kind: light
embed: 64
layers: 3
completion:
epochs: 100
batch: 512
lr: 1.0e-3
weight_decay: 1.0e-5
usage: 1.0
balance: 1.0
grad_clip: 1.0
val: 0.1
patience: 10
recommendation:
epochs: 100
batch: 1024
lr: 1.0e-3
weight_decay: 1.0e-5
negatives: 1
grad_clip: 1.0
val: 0.1
patience: 10
eval:
ks: [10, 20]
robustness: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
ablations: [no_retrieval, no_pe, no_codebook]
serve:
host: 0.0.0.0
port: 8080
workers: 1
log:
level: INFO
structured: true
directory: runs
Load it:
from morel import Config
config = Config.load("configs/synthetic.yaml")
Or from the CLI:
python -m morel train completion --config configs/synthetic.yaml
Programmatically
from morel import Config
config = Config.defaults()
config = Config.from_dict({...}) # from a nested dict
config = Config.from_yaml("path.yaml") # convenience, same as Config.load
Config.defaults() returns a fully populated Config with every
field at its shipped default. Field-level overrides work too:
from dataclasses import replace
from morel import Config
config = Config.defaults()
config = Config(masking=replace(config.masking, ratio=0.6))
Because Config.__post_init__ calls validate(), a ratio outside
[0, 1] raises Cfg at construction time, not somewhere downstream.
Override at runtime
From environment variables
config = Config.env()
Recognised variables: MOREL_SEED, MOREL_DEVICE. For more than
two overrides, use a YAML file.
On the CLI
Every subcommand accepts --config and an optional
--epochs / --items / --users override that swaps the matching
field without rewriting the config on disk. The recorded run
manifest always reflects the resolved config, not the override.
Save a config
config.save("configs/my.yaml")
The YAML round-trips bit-exactly through Config.load, so a
downstream Config.hash() is stable across the save / load cycle and
the manifest's cfg_hash field binds a run to its config.
Field reference
See Reference: config for the full table of fields with a one-line description of each.