-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Is your feature request related to a problem? Please describe.
Hi, first of all, this project has a great potential for ML project configuration! Well done <3!!!
There is one usecase that is quite common in ML. It is when you have two different sub-configurations and you want to easily switch between them and then also specify certain sub-options. For example, consider a ML training script where you want to be able to select different optimizers:
class Optimizer(BaseModel):
lr: float = 0.001
eps: float = 1e-7
class Adam(Optimizer):
lr: float = 0.003
class SGD(Optimizer):
lr: float = 0.002
class Config(BaseModel):
optimizer: Adam | SGD = Adam()
Now it would be awesome to somehow specify which optimizer to initialize in the config and also be able to set some of its parameters.
Describe the solution you'd like
How the CLI should look:
python train.py --optimizer adam --optimizer.lr 0.01 # specify the optimizer type and then also specify some of its params
There may be an issue regarding naming of the arguments based on the Union type. Instead, perhaps enums could be used:
class Optimizers(Optimizer, Enum):
adam = Adam()
sgd = SGD()
sgd_custom = SGD(lr=1.0)
class Config(BaseModel): # this gets parsed by argdantic into a cli later
optimizer: Optimizers = Optimizers.adam
The CLI would have to check that the enum value itself is a BaseModel and treat it as a nested configuration node to be displayed and available in terminal.
Describe alternatives you've considered
Hydra allows this kind of sub-grouping via subfolders. Simple-parsing solves it via subgroups type. Unfortunately, none of them are built on pydantic, so the user has to take care of validation themselves.
WDYT about the feature? It would allow quite complex configurations, for example:
python train.py \
--optimizer adam | sgd \
--optimizer.lr 0.1 \
--encoder lstm | conv \
--encoder.channels 512
Edit: after a bit of thought, perhaps the Annotated type could be better suited 🤔 It would be something like
class Config(BaseModel): # this gets parsed by argdantic into a cli later
optimizer: Annotated[Optimizer, argdantic.Subgroups(adam=Adam(), sgd=SGD), sgd_custom=SGD(lr=1.0))] = Adam()
The advantage is that this can be used outside of CLI world without issues - one would be able to initialize Config without the need to import the enum class. It would be simply Config(optimizer=SGD(0.1)) instead of Config(optimizer=Optimizers.SGD). Another advantage is that it would be possible to pass optimizer config that is not pre-defined in the Enum.