coma
: Configurable command management for humans.
Introduction
coma
makes it easy to build configurable command-based programs in Python.
Commands (also known as sub-commands) are the commit
and pull
part of
git commit
and git pull
(whereas git
is the program). Commands can
be seen as command-line meta-arguments: They drastically affect not only the
behavior of the program, but also what additional command-line line arguments
and flags are accepted.
coma
goes one step further. Each command implicitly determines which configuration
files are loaded, enabling command-specific configs that don’t affect the whole
program.
Why coma
?
coma
has three key features that enable rapid prototyping while maintaining rich flexibility:
- Rich configuration awareness. Configurations leverage omegaconf’s extremely rich and powerful configuration management features.
- Abstracted boilerplate. Command selection abstracts away the
argparse
boilerplate, while retaining full interoperability for complex use cases. - Plug-and-play extensibility. Hooks enable plug-and-play flexibility to tweak, replace, or extend
coma
’s default behavior.
Why choose coma
over another solution, like
hydra? hydra
, specifically, has the following
limitations (all of which are features that coma
supports!):
- Commands.
hydra
lacks commands. Related functionality must be implemented as separate programs.coma
naturally encourages component reuse. - Command-line arguments and flags.
hydra
requires that all program data be provided through configs, whereascoma
natively supports command-line integration in addition to configs. - Parallel and independent configs. All
hydra
configs must be hierarchical, whereascoma
encourages greater flexibility with its config structure.
Installation
pip install coma
Testimonial
I developed coma
to rapidly prototype and iterate my deep learning research projects. I have been using it for every project since.
I use coma
to split my workflow into discrete steps, such as preprocess
,
train
, and eval
. Each step maps cleanly onto a coma
command, which
only loads configs necessary to that step. This separation of concerns enables
me to focus of producing impactful research, instead of getting bogged down in the
minutiae of implementation details.
For example, my project codebase might have the following structure:
src/
|-- my_proj/
| |-- preprocess.py
| |-- train.py
| `-- eval.py
`-- main.py
Inside each file in my_proj
, I’ll define a command and a config for that step in my workflow. For example, train.py
might have:
from dataclasses import dataclass
@dataclass
class TrainConfig:
# Define a feature rich config that is fully omegaconf-compatible.
lr: float = 1e-05 # For example, a default learning rate for training.
def train(cfg: TrainConfig):
... # Use `cfg' in your training code (e.g., setting the learning rate).
In main.py
, only a single line of code is required to enable each command to access all the rich functionality of coma
:
from my_proj import preprocess, PreprocessConfig, train, TrainConfig, eval, EvalConfig
import coma
if __name__ == "__main__":
coma.register("preprocess", preprocess, PreprocessConfig)
coma.register("train", train, TrainConfig)
coma.register("eval", eval, EvalConfig)
coma.wake()
For example, we can change the learning rate to 1e-06
with a simple command-line override:
python main.py train lr=1e-06
No need for argparse
boilerplate! coma
handles everything in the background.
Getting Started
Excited to learn more? Jump straight into the short introductory tutorial.