Replies: 2 comments 1 reply
-
"Can functional expressions replace the defaults list" is a good question to ask. The short answer is "yes, partially". Hydra's defaults lists integrate two core functionalities:
The "config merging and organization" part can certainly be handled by functional expressions. The functional operators can be implemented using OmegaConf's variable interpolations and custom resolvers. The "config discovery and loading" part would be trickier to implement using pure functional expressions. The reason is that Hydra's config discovery/loading depends on program state (see Config Search Path docs). For example, a defaults list If you are only interested in loading configs from local Below I'll illustrate the use of OmegaConf's custom resolvers to implement the workflow you proposed. We'll define a few yaml files # optimizers.yaml
adam:
_target_: optim.Adam
lr: 0.3
eps: 1e-5 # config.yaml
name: 'root_finder'
algorithm:
_target_: alg.GradientBased
# Below we use custom resolvers `load` and `merge`, implemented in app.py
optimizer: ${merge:${load:optimizers,adam},${_optimizer_overrides}}
_optimizer_overrides:
lr: 0.1 # app.py
from omegaconf import OmegaConf
# Here we implement the custom resolvers `load` and `merge`:
def _load_impl(file_name: str, key=None):
"""
Load yaml file `file_name` from disk. Append suffix ".yaml" to `file_name` if necessary.
If `key` is given, select `key` from the loaded config.
"""
# load the yaml file from disk
if not file_name.endswith(".yaml"):
file_name = f"{file_name}.yaml"
cfg = OmegaConf.load(file_name)
# select the given key from the loaded config
if key is not None:
return OmegaConf.select(cfg, key, throw_on_missing=True)
else:
return cfg
def _merge_impl(*args):
return OmegaConf.merge(*args)
OmegaConf.register_new_resolver("load", _load_impl)
OmegaConf.register_new_resolver("merge", _merge_impl)
# Now we load `config.yaml` and print the result.
conf = OmegaConf.load("config.yaml") # OR @hydra.main(config_path=".", config_name="config")
OmegaConf.resolve(conf)
print(OmegaConf.to_yaml(conf)) Running the app yields the following result:
|
Beta Was this translation helpful? Give feedback.
-
@Jasha10, when you say Also, would this functional resolution work with structured schemas and command line overrides? What functionality would exactly be limited by functional resolution? |
Beta Was this translation helpful? Give feedback.
-
This started as a comment on #2227 that @Jasha10 asked me to open a discussion on.
Hydra allows a kind of functional expression in config in the form of OmegaConf interpolations, but these cannot evaluate to further nested config but just to a value for a config key. It seemed to me that allowing more powerful functional expressions could obviate the need for the defaults list and solve the issue that currently you are forced to choose between using the defaults list and normal config depending on whether you want overriding to work by replacement or merging.
To repeat my comment, what if (instead of using the defaults list) you could do something like
Or, if you wanted to reuse these optimizer configs in different places, you might have an
optimizers.yaml
file, and then you would put the contents of theoptimizers
key there and then do:Or, if you needed to override the learning rate,
Due to the limitations of yaml syntax, it probably makes sense to not allow nesting dict expressions inside "functional" expressions but instead require them to be assigned to a variable, like
_optimizer_overrides
. Also, I'm using the convention here that underscored config is for internal use, but there could be a way to make_optimizer_overrides
actually not be in the output config (if that is not already possible).Note also that here I use
@{optimizers/adam}
to mean theadam
key in theoptimizers.yaml
file in the current directory. Ifoptimizers.yaml
were in thetraining
subdirectory of the current directory, you could use@{training/optimizers/adam}
. And you could use..
and absolute paths as well. To reduce ambiguity, it might be better to use:
instead of/
to separate the path to the yaml file from key inside the file, i.e.,@{optimizers:adam}
instead of@{optimizers/adam}
.Beta Was this translation helpful? Give feedback.
All reactions