reqm
Ridiculously Easy Quant Manager
Directory-based config management and object factory built on Hydra.
Install
pip install reqm
The problem
Hydra is excellent for config-driven instantiation. But using it as a general object factory requires ceremony:
# You have to do all of this just to instantiate one object
with hydra.initialize(config_path="conf"):
cfg = hydra.compose(config_name="my_model")
model = hydra.utils.instantiate(cfg.model)
This ceremony means Hydra stays in the lab. It's awkward in a notebook, verbose in a service, and doesn't belong in production call sites.
reqm gives you Hydra's power — config-driven instantiation, composable overrides, recursive object graphs — with none of the ceremony:
from reqm import QuantManager
import my_configs
QM = QuantManager(my_configs)
model = QM.build("summarizer_prod")
Same call in a notebook, a FastAPI endpoint, a test, or a batch job.
Core concept: the Quant
A Quant is the unit reqm builds and manages. It is:
- Callable — invoked directly with its inputs
- Config-driven — constructor arguments defined in YAML, no hardcoding
- Auditable — implements
dummy_inputs(), example inputs the factory uses to verify it actually runs
from reqm import Quant
from reqm.overrides_ext import override
class Summarizer(Quant):
def __init__(self, model_name: str, max_tokens: int):
self.model = load_model(model_name)
self.max_tokens = max_tokens
@override
def dummy_inputs(self) -> list[dict]:
return [{"text": "The quick brown fox jumps over the lazy dog."}]
@override
def __call__(self, text: str) -> str:
return self.model.summarize(text, max_tokens=self.max_tokens)
The dummy_inputs contract is what separates a Quant from a plain ABC. reqm can call each Quant with its own dummy inputs at build time — if it fails, it fails early and loudly, not silently in production.
Config modules and QuantManager
A config module is any importable Python package containing YAML files:
my_configs/
├── __init__.py
├── summarizer_prod.yaml
├── summarizer_fast.yaml
└── serving/
└── prod.yaml
Each YAML config declares what to build:
# @package _global_
_target_: myproject.models.Summarizer
model_name: gpt-4o
max_tokens: 512
QuantManager takes the config module and gives you a uniform API. Construct it once in the __init__.py next to your configs directory, then import QM everywhere:
# myproject/__init__.py (next to configs/)
import myproject.configs as configs
from reqm import QuantManager
QM = QuantManager(configs)
# Any call site — notebook, script, service, test
from myproject import QM
QM.list_configs() # ["serving/prod", "summarizer_fast", "summarizer_prod"]
QM.validate() # check all configs have # @package _global_
cfg = QM.get_config("summarizer_prod") # resolved OmegaConf DictConfig
obj = QM.build("summarizer_prod") # instantiated object
Configs can compose other configs via Hydra defaults lists:
# @package _global_
defaults:
- /base_model@child
- _self_
_target_: myproject.models.Ensemble
weight: 0.6
The uniform call site
The core value proposition: ONE script, swap the config name, get different experimental results. No code changes, no if/else chains, no factory functions.
Construct QM once in the __init__.py right next to your configs directory:
# myproject/__init__.py (lives next to configs/)
import myproject.configs as configs
from reqm import QuantManager
QM = QuantManager(configs)
Then every script just imports it:
import sys
from myproject import QM
model = QM.build(sys.argv[1]) # <-- only this string changes
result = model(text="Hello world")
python evaluate.py summarizer_prod
python evaluate.py summarizer_fast
python evaluate.py summarizer_experiment_v3
Runnable example
The repo includes a complete example project at examples/estimators/ that demonstrates Quant subclasses, non-Quant configurable dependencies (Filters), Hydra config composition, and multiple scripts sharing a single QM instance defined in examples/estimators/__init__.py:
# Evaluate a single estimator config
uv run python -m examples.estimators.scripts.evaluate mean_simple
# Inspect the fully resolved config YAML
uv run python -m examples.estimators.scripts.inspect_config ensemble/mean_median
# Compare multiple configs side by side
uv run python -m examples.estimators.scripts.compare mean_simple mean_outlier median_simple
# Validate all configs
uv run python -m examples.estimators.scripts.validate_configs
# Sweep all configs and rank by performance
uv run python -m examples.estimators.scripts.sweep
PyTorch integration
reqm does not depend on PyTorch, but its primary use case is config-driven model experimentation with nn.Module. The repo includes a TorchQuant bridge class that resolves the __call__ vs forward() conflict — subclass it instead of plain Quant when your model is an nn.Module:
Don't subclass TorchQuant directly for every model — create a domain base class that locks the forward signature for your use case:
from myproject.torch_quant import TorchQuant # copy from examples/
# Domain base — locks forward(self, x: Tensor) -> Tensor for all regressors
class Regressor(TorchQuant):
in_features: int
@override
@abc.abstractmethod
def forward(self, x: torch.Tensor) -> torch.Tensor: ...
@override
def dummy_inputs(self) -> list[dict]:
return [{"x": torch.randn(4, self.in_features)}]
# Concrete model — must match the Regressor signature
class LinearRegressor(Regressor):
def __init__(self, in_features: int):
super().__init__()
self.in_features = in_features
self.linear = nn.Linear(in_features, 1)
@override
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.linear(x)
TorchQuant.forward uses @allow_any_override so domain bases can narrow freely. Once the domain base locks the signature (without @allow_any_override), all concrete models must match — enforced at class definition time, not runtime.
See docs/torch_integration.md for the full explanation, and examples/torch_models/ for a runnable example:
uv run python -m examples.torch_models.scripts.evaluate linear_simple
uv run python -m examples.torch_models.scripts.evaluate mlp_small
uv run python -m examples.torch_models.scripts.audit
Why not just Hydra?
Hydra is framework-first. It expects to own your program's entry point. reqm is library-first — it has no opinion about your application structure and works wherever Python runs.
| Hydra | reqm | |
|---|---|---|
| Object instantiation | yes | yes |
| Config composition | yes | yes (via Hydra) |
Auditability (dummy_inputs) |
no | yes |
| Works in notebooks | limited | yes |
| CLI ceremony required | yes | no |
Publishing
To release a new version to PyPI:
- Bump the version in
pyproject.toml - Build and publish:
uv build
uv publish --token pypi-YOUR_TOKEN
Name
reqm is also a nod to Rue Esquermoise, one of the oldest streets in Lille, France, dating to the 13th century. Its etymology traces to the Flemish eskelm — "frontier." A fitting name for a library that sits at the frontier between research and production.
Status
Core API implemented: Quant, QuantManager, config composition, and override support all work. See examples/estimators/ for a complete working project.
Metadata
Release files for reqm 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| reqm-0.1.1.tar.gz | 61.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| reqm-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 74.4 kB
Release files / reqm-0.1.1.tar.gz
| Download URL | reqm-0.1.1.tar.gz |
|---|---|
| Size | 61.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a6c86742299ec031c044c0fa6bdb2ea09671bffed24f38bec2dae2f090fa3e27
|
|
BLAKE2b-256 checksum How to use checksums |
02dd1deff9574936c7d55ca2a31c438f105e71bc03e5d93d9d6939a5404a63cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / reqm-0.1.1-py3-none-any.whl
| Download URL | reqm-0.1.1-py3-none-any.whl |
|---|---|
| Size | 12.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
56b4fc7896951a28ca4c241a25a27fbc85d7b13eec618a05cf24a06e411b7455
|
|
BLAKE2b-256 checksum How to use checksums |
9f3add33b3de269047469a23e4d987a01d0b865405138d83924759fce8740622
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|