-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Overview
This RFC proposes to change how we handle sub-configs in order to make them more flexible. Instead of treating a sub-config as a sub-experiment that is just run as is, this proposal is about using them as definitions that can then be flexibly used in the remaining config.
Example
# Define sub-configs to use them later
nitrogen:
...
cyclobutadiene:
...
short_training:
...
long_training:
...
model1:
...
model2:
...
# The user has to specify how to use the sub-configs
load:
- model1 # directly specifying a sub-config means always using it (like `fixed`)
- choice:
- nitrogen
- cyclobutadiene
- choice:
- short_training
- long_training
grid:
other_attribute:
type: choice
options:
- True
- FalseConsiderations
We currently assume that always exactly one sub-config is chosen. This proposal allows users to define themselves how they want to combine sub-configs. Specifying them all in a grid would replicate the behavior we had previously, so this is a natural extension.
A sub-config can itself contain fixed/grid/random blocks and further sub-configs, just like they do now. The outer set of configs is then combined with the inner set of configs (outer product), just like now. I.e. loading a single sub-config can result in multiple configs, if the sub-config contains a grid.
Including separate files
This also naturally extends to loading separate config files into one config. The other config file can be treated exactly the same way as a subconfig. The user would only have to provide a keyword, specifying that this is now an external file. I.e.
# Define sub-configs
nitrogen:
...
model2:
...
load:
- model2
- file: ~/test/general.yaml # A full config file, with fixed, grid, and random blocks.
- choice:
- nitrogen
- simple_file: ~/test/dataset2.yaml # A simple config file, which only containes fixed parameter values, similar to what Sacred uses.Possible variant
While defining sub-configs seems pretty clear (that's exactly how we do it currently), specifying their usage still remains an open question. Instead of creating a new top-level block load, we could also integrate loading sub-configs into the fixed/grid/random blocks by introducing a special load keyword. However, this is much more difficult, considering the restrictions of yaml (every key has to be unique).
fixed:
model1: load # Always use everything from one sub-config
grid:
dataset: # The name doesn't do anything, but it has to be unique (due to yaml)
type: load # Specifies that we want to load sub-configs
options:
- nitrogen
- cyclobutadiene
- file: ~/test/general.yaml
- simple_file: ~/test/dataset2.yaml
training:
type: load
options:
- short_training # Multiple sub-configs can be combined
- long_trainingI prefer the original suggestion. It also seems to align better with user expectations. With this variant, loading a sub-config in the fixed block could lead to multiple different configs, which might be unexpected.
Open questions
There are 2 open questions:
- What is the best way of specifying
loadfor fixed/grid/random? How do we best specify importing files in these 3 cases? -> No random; use keywordsfixedandchoice. - How to best handle conflicting parameters? We could (1) always raise an error if there are conflicting parameters in separate sub-configs or the config vs. the sub-config. Or (2) we handle them like we currently do, by treating sub-configs as a hierarchy and using the deepest parameter definition, if there is a purely descending path between them (but show a warning). Otherwise, we raise an error.