-
-
Notifications
You must be signed in to change notification settings - Fork 629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable instantiations without resolution #2268
Comments
Hi @kpoeppel, |
I faced similar problem as well considering the script below func:
_target_: my_module.train
# Only able to discover num_class during runtime
num_classes: -1
model:
num_class: ${num_class} def train(cfg):
# assuming ret = 10
cfg.num_class = automatic_detect_num_class()
assert cfg.model.num_class == 10
# False, because call resolved all interpolation
@hydra.main(config_path="configs", config_name="config", version_base="1.2")
def main(cfg: DictConfig) -> None:
# dynamically trigger function based on config
call(cfg.func, cfg=cfg)
|
Image you have an experiment that you want to use multiple loggers with, in a configurable way. The def construct_loggers(cfg):
loggers = []
for logger in cfg.loggers:
loggers.append(hydra.utils.instantiate(logger, cfg=cfg, _recursive_=False))
You now want to hand over the complete configuration (resolved once) to the logger. The problem now is, that cfg is integrated into the DictConfig of logger, which sets a different top level, so resolution doesn't work anymore. @24hours : Thanks for the idea for a workaround. |
Let me make sure I understand correctly: |
I am sorry that my example changed slightly from the original post to the first reply. The goal is to use the configuration to choose among loggers, that take the unresolved configuration as an argument. # config.yaml
logger:
_target_: main.LoggerA
cfg: ${oc.eval:'OmegaConf.to_yaml(cfg)'} # main.py
from omegaconf import OmegaConf, DictConfig
import hydra
from typing import Optional
cfg: Optional[DictConfig] = None
# main.py
class LoggerA:
def __init__(self, cfg):
self.cfg = cfg
# .. do some logging
def log(cfg):
logger = hydra.utils.instantiate(cfg.logger, _recursive_=False, _resolve_=False)
return logger
def oc_eval(expr, _globals, _locals):
try:
# print("EvalExpr", expr, _globals, _locals)
return eval(expr, _globals, _locals)
except BaseException as err:
print(err)
return None
@hydra.main(config_path=".", config_name="config")
def main(conf: DictConfig) -> None:
global cfg
OmegaConf.register_new_resolver("oc.eval", lambda expr: oc_eval(expr, globals(), locals()))
cfg = conf
OmegaConf.resolve(conf)
print(conf)
log(cfg)
if __name__ == "__main__":
main() |
I see. from omegaconf import OmegaConf
def oc_eval(expr, _globals, _locals):
try:
# print("EvalExpr", expr, _globals, _locals)
return eval(expr, _globals, _locals)
except BaseException as err:
print(err)
return None
OmegaConf.register_new_resolver(
"oc.eval", lambda expr: oc_eval(expr, globals(), locals())
)
cfg = OmegaConf.create(
"""
logger:
cfg: ${oc.eval:'OmegaConf.to_yaml(cfg)'}
"""
)
print(f"CONFIG 0: {cfg}")
OmegaConf.resolve(cfg)
print(f"CONFIG 1: {cfg}")
OmegaConf.resolve(cfg)
print(f"CONFIG 2: {cfg}")
OmegaConf.resolve(cfg)
print(f"CONFIG 3: {cfg}") Running this script results in the following output:
This feels fairly pathological to me. |
How about the following as a workaround? def log(cfg):
logger = hydra.utils.instantiate(cfg.logger, cfg=cfg) # pass cfg explicitly
return logger |
Interesting. Thanks for the additional datapoint @24hours! |
This can only be used with |
Cross link to issue #1758, which is also related to problems with |
🚀 Feature Request
Add a flag
_resolve_
tohydra.utils.instantiate
to optionally disable theOmegaConf.resolve
part.Motivation
Sometimes one wants to add some self-references to the configuration, e.g. instantiating a logger with all the configuration.
For this kind of instantiation it would be nice to have a
_resolve_
flag, which can be set tofalse
. Otherwise the top level of the configuration is different, which leads to resolution errors.Pitch
Describe the solution you'd like
Adding this flag enables simple configuration self-references without infinite recursions (in conjunction with an
eval
resolver). As the flag should be true by default, the current usual behaviour is unchanged.Describe alternatives you've considered
It might be possible to do this in code, but that's not the point of configurability. Already this kind of solution requires code modifications (
cfg
variable in the respective namespace).Are you willing to open a pull request? (See CONTRIBUTING)
yes
The text was updated successfully, but these errors were encountered: