-
-
Notifications
You must be signed in to change notification settings - Fork 642
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
Implement #1389 or similar functionality #1939
Comments
Hi @somedadaism,
The way originally asked for proposes that, with the following config, the db group would produce a ListConfig object containing each of the mysql and postgresql input configs: defaults:
- base_config
- db:
- mysql
- postgresql This will not be possible because there is already a different behavior implemented for nested lists within a defaults list (such as the nested list Admittedly I have not yet had a chance to look closely at later discussion in comments on the linked issue #1389. |
Hi @Jasha10 thanks for your quick reply.
With:
What currently works is:
resulting in:
What I want to create as output is:
Now I understand that:
Can not work as it (correctly!) results in:
which is what I believe you also pointed out.
will result in:
and not in
I believe the ability to merge configs into lists is very important to avoid repeating oneself for ML applications of hydra, but there seems to be no way to merge them. |
Take a look at oc.dict.values, it may be what you are looking for. |
Hello @omry thank you for creating hydra and for taking a look. :)
Then:
Would be text substituted to:
Just as in the situation:
The defaults list in:
are text substituted to:
I know what I ask for is not how it works but I believe it would be the more natural and consistent way.
Then:
Would be text substituted to:
|
The current behavior is probably due to the implementation of >>> from omegaconf import OmegaConf
>>> OmegaConf.merge([1,2], [3,4])
[3, 4]
>>> OmegaConf.merge({"a": [1,2], "b": [3,4]}, {"b": [5,6], "c": [7,8]})
{'a': [1, 2], 'b': [5, 6], 'c': [7, 8]} mappings on the left are updated by mappings on the right; sequences on the left are overwritten by sequences on the right. I agree with you that, in the specific case of "Selecting multiple configs from a Config Group" in the defaults list, it would be more useful to concatenate ListConfigs instead of overwriting them (as you have outlined above). The proposed change would technically be breaking, but I doubt anyone is relying on the old behavior. This being said, I'm not sure that special-casing the "selecting multiple configs from a config group" behavior is the most general solution to the use-case you've highlighted. It still feels like a hack that # my_callback_1.yaml
- my_param1: 1 Painfully, we are prevented from using a defaults list in You are trying to achieve the following result: # config.yaml
defaults:
- append callbacks: my_callback_1
- append callbacks: my_callback_2 Here an "append" keyword would signify that the # my_callback_1.yaml
defaults: ... # possible defaults list
my_param1: 1 # no leading dash Edit: I should mention that I don't personally have the bandwidth to work on implementing such a feature for the next Hydra release. |
I think the proposed syntax is very good. |
Unfortunately, I fear that the implementation of this feature might not be straight-forward; it will require adding a new keyword to the |
Cross-link to #1547 which is related. |
@Jasha10 @jieru-hu I agree with @somedadaism that this feature is very much needed for ML applications. We often pass a list of callbacks to a trainer, and being able to compose such a list via the command line is necessary. Given the huge number of combinations one can derive from a list (e.g. for 5 callbacks, there are 32 combinations), it's impossible to have a YAML for each combination. @Jasha10 If it's not easy to implement this feature, is there an acceptable workaround in the meantime? For example, I would like to specify a default list of callbacks in a primary config and couldn't figure out a way to do it yet. # cb1.yaml
_target_: torch.nn.Identity
arg1: 1 # cb2.yaml
_target_: torch.nn.Identity
arg2: 2 # config.yaml
defaults:
- callbacks:
# what to put here? The desired output looks like callbacks:
- _target_: torch.nn.Identity
arg1: 1
- _target_: torch.nn.Identity
arg2: 2 |
@tangbinh, see Omry's comment above. Basically, you should use the defaults list to compose a dictionary whose values are the callbacks you want. You then can use the
# config.yaml
defaults:
- callbacks@_callback_dict.cb1: cb1
- callbacks@_callback_dict.cb2: cb2
- _self_
callbacks: ${oc.dict.values:_callback_dict} # my_app.py
import hydra
from omegaconf import OmegaConf
@hydra.main(config_path=".", config_name="config")
def app(cfg):
OmegaConf.resolve(cfg)
del cfg._callback_dict
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
app()
|
@Jasha10 Thank you for working out the example. It's certainly helpful, although I think we all agree that invoking If possible, would we be able to prioritize this list composition feature a bit? I believe ML users would run into this issue quite often. |
Thanks for the nudge :)
Here's the trick: $ python my_app.py +callbacks@_callback_dict.cb3=cb3
callbacks:
- _target_: torch.nn.Identity
arg1: 1
- _target_: torch.nn.Identity
arg1: 2
- _target_: torch.nn.Identity
arg1: 3 The plus symbol is for appending to the defaults list. $ python my_app.py '~callbacks@_callback_dict.cb1'
callbacks:
- _target_: torch.nn.Identity
arg1: 2 |
# config.yaml
defaults:
- callbacks@_callback_dict.cb1: cb1
- callbacks@_callback_dict.cb2: cb2
- _self_
callbacks: ${oc.dict.values:_callback_dict} Hi, in this example, is there a way to avoid writing |
Hi @Yevgnen, |
Thanks for bringing this discussion back, it has been quite useful. I like the I want to point out that if this new functionality is added, it may also be natural to add
Not sure this is great, I personally feel the |
The workaround here doesn't work nicely with structured config. Unless the config also have a |
Summary: Currently, flsim cannot handle a list of configs Eg: a json config like the following is not supported. ``` { "trainer": { "clients": [ {"_base_": "base_client", "optimizer": {"lr": 0.1}}, {"_base_": "base_client", "optimizer": {"lr": 0.2}}, ] } ``` The one hiccup in supporting this is hydra still doesn't support overriding/appending lists when values are configs. (see facebookresearch/hydra#1939 (comment)) In order to overcome the above, we treat the list as a dictionary with the key as list index. The above config in yaml format will look as follows: ``` trainer: ... clients: '0': _target_: flsim.clients.base_client.Client _recursive_: false epochs: 1 optimizer: _target_: ??? _recursive_: false lr: 0.1 momentum: 0.0 weight_decay: 0.0 lr_scheduler: _target_: ??? _recursive_: false base_lr: 0.001 max_clip_norm_normalized: null only_federated_params: true random_seed: null shuffle_batch_order: false store_models_and_optimizers: false track_multiple_selection: false '1': _target_: flsim.clients.base_client.Client _recursive_: false epochs: 1 optimizer: _target_: ??? _recursive_: false lr: 0.1 momentum: 0.0 weight_decay: 0.0 lr_scheduler: _target_: ??? _recursive_: false base_lr: 0.001 max_clip_norm_normalized: null only_federated_params: true random_seed: null shuffle_batch_order: false store_models_and_optimizers: false track_multiple_selection: false ... ``` Reviewed By: Anonymani Differential Revision: D37638999 fbshipit-source-id: 5444da742742d4cc976875a6dc055a0c71c186e4
Do you mind explaining the workaround you used with structured config? |
@TesnimHadhri I eventually did not use it, but I remember having a |
I see, thanks for the quick answer! |
@Jasha10 Hi, is it possible for you to provide a brief update on the status of the implementation of this feature? Should we look into it as you commented earlier?
|
Note for the ones still seeking for a better solution: Lightning-Hydra-Template implements another workaround which is however still based on a dictionary with redundant keys. The difference between the solution suggested by @Jasha10 above is that the dict is parsed internally by a custom instantiator rather than relying on |
That's the workaround I am resorting to as well. Still hope this feature can be implemented. |
Bumping this because I've ran into this on two completely unrelated projects now :( |
I also would find this extremely useful: anywhere a functional style is used it is useful to specify an ordered list of items. As well as callbacks, pipelines of preprocessing transformations seem like a natural use case. Do the current workarounds preserve the order of the composed items? This is critical in such cases but I'm unclear whether the fact that dictionaries are involved in intermediate steps means that the order is not preserved |
🚀 Feature Request
I would like to ask if it is possible to implement the functionality asked for in #1389
Motivation
I believe the feature is extremely useful for ML applications. To be able to have list composition in the defaults list the way we already have dict composition would allow to be less redundant in the configuration by reusing config files more.
Pitch
I know that #1389 had been closed as invalid but it seems that in omegaconf 2.1 the necessary prerequisites maybe have been implemented since the issue had been closed.
This could maybe be used to allow for list composition in the defaults list in the way originally asked for instead of using
os.dict.values
in a hacky fashion, like proposed e.g. by Max Ehrlich here:https://stackoverflow.com/questions/64802586/how-to-gather-config-files-in-a-list-with-hydra-fb
Are you willing to open a pull request?
Maybe if I can get sufficient guidance I would try.
The text was updated successfully, but these errors were encountered: