Search code examples
pythonfb-hydrahydra-core

How to create cli to access multi cli commands using hydra?


I want to package the repo and provide a cmd-line entry point for all the separate tasks managed by hydra. Let me explain with an example. I have multiple tasks that are all powered by hydra. Each task has 3 possible operations. Let's look at only 2 for simplicity- training and inference I can run them like this

python train.py args.epochs=2 ... # edit default params via hyda
python infer.py ...

Now I want to package this repo and create a cli interface that can access all these tasks and support the same ease of use as hydra. Something like this

yolov5 train  --args.epochs=2 # should be same as python detect/train.py --args.epochs=2 ..
yolov5 infer --args.conf=0.2

Up until now, I would use fire CLI to create console entry points. But combining fire with hydra doesn't work. If I try to initialize fire with a function decorated by hydra main, it expects cfg as manual cmd-line input rather than hydra reading the default config.

# train.py
@hydra.main(...):
def run(cfg):
    ...
fire.Fire({
        'classify/train': yolov5.train.run,
        }) # Throws error that cfg must be passed

Another way that I can think of is directly adding console entry points to the hydra.main() decorated function. But that would really populate the global cli space. So, is there a clean and simple way of supporting this use case? Ideally, I'd like to use only hydra to manage this but open to combining other tools if absolutely necessary.


Solution

  • Hydra doesn't support a standalone "command" argument. The general pattern is to add an action or mode config option which enumerate the supported tasks.

    @hydra.main(...)
    def main(cfg):
      if cfg.action == "train":
        ...
      elif cfg.action == "test":
        ...
    

    You can populate entry points as you suggested. You can see an example here. (Page has a link to a working example)

    You can get closer to the user experience you are describing using use a script or a shell alias to convert something like my_app mode to my_app action=mode to make the user experience similar to what you are trying to achieve.