-
-
Notifications
You must be signed in to change notification settings - Fork 662
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
Reproducing a Hydra run from previous Hydra job configs #1805
Comments
This is not an officially supported workflow. Try overriding the run path as well from the command line.
|
Hi, how can I load the config with properly formatted placeholders like |
@Yevgnen see OmegaConf.load. |
config/config.yaml work_dir: ${hydra:runtime.cwd}
when: ${now:%Y-%m-%d}/${now:%H-%M-%S} main.py # -*- coding: utf-8 -*-
import hydra
from omegaconf import DictConfig
@hydra.main(config_path="config", config_name="config")
def main(cfg: DictConfig) -> None:
print(cfg.work_dir)
print(cfg.when)
if __name__ == "__main__":
main() @Jasha10 Hi, I tried to load
And I don't seem to see any information related to the interpolated values of |
@Yevgnen thank you for trying it out and the repro code. Could you provide a bit more details on what you tried with OmegaConf.load so we can repro? Many thanks |
reopening, we should look into this and at least provide some documentation on the approach. |
I've had success reproducing the config by using the saved
This produces a file - a=b
- +c/d=e This list of overrides can be used to reproduce the config. The following recipe has worked for me: with hydra.initialize(config_path=config_path): # same config_path as used by @hydra.main
recomposed_config = hydra.compose(
config_name="main", # same config_name as used by @hydra.main
overrides=OmegaConf.load("outputs/.../.hydra/overrides.yaml"),
) There are a few caveats here:
|
how about we jus save the final composed config of everything related to a job in a separate YAML file (everything including Hydra and the job config, all resolved, no OmegConf syntax in the YAML) we can also provide an experimental CLI option for rerun an application from that finalized composed config. we will only support single run for now and see how it goes. Saving the finalized YAML will also help with debugging, I've heard from users that the YAML files saved has OC resolvers in them and sometimes is hard to figure out what's going on. |
Saving a resolved yaml config (e.g. That being said, creating Another potential complication is that some application use-cases could rely on interpolations or OmegaConf resolvers being unresolved, e.g. if the user app wants to call these resolvers at runtime. For re-running the application, more information is needed than just what is in |
thanks @Jasha10 those are great points! I agree that eagerly resolve all configs is not the best way to go - especially when user applications also plays a role here. |
I think that using a
To pickle before the run, we might need to change the signature of the |
I think for now we can just pickle the config object instead of a uncomplete JobReturn - that seems like it should be enough (both task and hydra config are included in the |
Hi @ashleve @Yevgnen |
I'm see three potential approaches suggested in this thread
I have some questions to better understand the differences between these approaches
Thanks everyone for the clarification! |
Approaches 1 involves a round-trip through To see some of the differences, you can experiment with round-tripping a config through yaml as follows: approach1 = OmegaConf.create(OmegaConf.to_yaml(original_config)) # round-trip through yaml Approach 1 will produce an untyped config (i.e. a config that is not structured). This means you'll miss out on the runtime type-safety that comes with structured configs. Also, you'll see a difference when calling routines such as >>> class MyEnum(Enum):
... foo = 1
...
>>> original_config = OmegaConf.create({"key": MyEnum.foo})
>>> assert isinstance(original_config.key, MyEnum)
>>> approach1 = OmegaConf.create(OmegaConf.to_yaml(original_config))
>>> assert approach1.key == "foo"
>>> assert isinstance(approach1.key, str)
>>> assert not isinstance(approach1.key, MyEnum) # approach 1 doesn't preserve enum values
If you use structured configs or enum values, I'd recommend against approach 1. Another difference between approaches 1 and 2 is that, if you refactor your python dataclasses or change your input yaml files, the result of approach 2 will change accordingly. Approach 2 reconstructs the config using Hydra's compose process; the output of that process can change if your dataclasses or your input yaml files change. Meanwhile, the result of approach 1 is always the same (as it depend only on the static
The docs do recommend using Actually, approach 2 can be adapted to work with import sys
...
# approach2 adapted to @hydra.main:
overrides: list[str] = list(OmegaConf.load("outputs/.../.hydra/overrides.yaml"))
sys.argv += overrides
@hydra.main(config_path=..., config_name="main") # use same config_path and config_name as you used in the original run
def my_app(cfg):
... I wonder if it would make sense for
Yes, using the There is also a fourth approach that combines a few of these ideas: you can use PickleJobInfoCallback to produce a In summary, here are the four discussed approaches for re-animating a config from a previous experiment: Approach 1: Run Hydra with
|
Thanks for clarifying this subtle difference - that makes a lot of sense
I'll have to think more about whether this is desirable for my ML experiments. Typically, I would plan to checkout the git commit of the original run before reproducing, in which case there couldn't be any changes to the application code
I agree it could definitely be convenient to officially support that pattern. Worth opening a new issue? |
Yes, that would be great, thanks! |
@Jasha10 For Approach 2, how can we pass the overrides path from command line since we may want the overrides dynamic |
@npuichigo I haven't tried it but this: #1022 seems relevant to your question and might help. |
the |
Hi,
Currently Hydra generates the following logs:
![image](https://user-images.githubusercontent.com/43458894/131483660-c5f2d506-db2c-4d40-aa87-df106e8e4d24.png)
When I want to reproduce the experiment, I can simply load the
config.yaml
:python run.py --config-path /logs/runs/.../.hydra --config-name config.yaml
The problem is,
config.yaml
doesn't contain the hydra logs output paths configuration, which means that after running the line above, the logging path will revert to default.Is there a workaround for that?
Is it possible to additionally load hydra specific config from some other path with a simple oneliner?
Thanks
The text was updated successfully, but these errors were encountered: