mit-ll-responsible-ai / hydra-zen

Create powerful Hydra applications without the yaml files and boilerplate code.
https://mit-ll-responsible-ai.github.io/hydra-zen/
MIT License
339 stars 15 forks source link

Passing explicit types to builds #431

Closed orperel closed 1 year ago

orperel commented 1 year ago

Hi @rsokl ,

Thank you for this great library! I've set up a config system on top of hydra-zen + tyro, which is based on dynamic dataclass configs and seems to work well so far.

One compatibility issue I hit a wall with, is as follows:

hydra-zen is cool with untyped args, but tyro has some restrictions. Specifically, for cases like torch.optim.Adam, creating a dynamic config with the builds function yields a dataclass with typing.Any for some of the fields, which tyro then interprets as fixed fields which cannot be read from the CLI.

Digging through the implementation, this seems to come from using get_typing_hints under the hood, which means some args types are missed and therefore marked as typing.Any.

This can be quickly validated:

> import torch
> typing.get_type_hints(torch.optim.Adam.__init__)  
  result = {dict: 3} {'foreach': typing.Union[bool, NoneType], 'maximize': <class 'bool'>, 'capturable': <class 'bool'>}
 'foreach' = {_GenericAlias} typing.Union[bool, NoneType]
 'maximize' = {type} <class 'bool'>
 'capturable' = {type} <class 'bool'>
# Some args missing: lr, betas, eps...

For the torch.optim.Adam case, I suppose some kind of typing can be inferred from the default value. In the general case, at the very least one could mark those types as Optional to hint tyro to accept them. However, I couldn't find a way to pass explicit type hints to fields onto builds(), and on the other hand, make_config() which does accept fields / ZenField shouldn't be used to generate objects with a target.

Specifically I'm using builds with populate_full_signature=False, so I'm already controlling which fields are filtered out (i.e. the params). One workaround may be to use builds to generate an initial dataclass config and then generate a new type with the same target and correct field types. That feels cumbersome however.

Any thoughts on how to fix this one?

EDIT: not pretty, but as a temp workaround - cloning the function type and adding missing annotations according to default type inference seems to work.

rsokl commented 1 year ago

Hi @orperel sorry for the delay in responding.

You have probably seen this already, but hydra-zen provides type refinement behavior for improved compatibility with Hydra's limited support for annotations. One option here is for hydra-zen's config-creation functions to expose an option to turn this type-refinement mechanism off altogether. The dataclass' types will be reflect exactly the annotations of the target's signature in this case.

Would this be sufficient, or are there times where you need to specify custom annotations?

rsokl commented 1 year ago

Closing this as inactive, but feel free to reopen!