Ravex
Checkpoint and resume for PyTorch training, from one decorator on the function
that trains. Inside that function nothing changes: Ravex notices the model, the
optimizer, the LR scheduler, the AMP scaler and the dataloader as they are
built, counts every optimizer.step(), and writes a checkpoint on the cadence
you configured. If the process dies, running the same command again picks up
where it stopped.
Install
pip install ravex
Ravex is pure Python and needs Python 3.11 or later. It does not depend on torch, so that it attaches to whatever build you already have (CUDA, ROCm, CPU) instead of pulling another one in.
Its default checkpoint engine is Moonclip,
installed with pip install "ravex[moonclip]". Moonclip publishes wheels only
for Linux x86_64; elsewhere it has to be built from source, and where it is not
installed Ravex falls back to torch_save on its own.
Use
import ravex
@ravex.train_loop(preemption_handler=True)
def train():
model = build_model()
optimizer = torch.optim.Adam(model.parameters())
for batch in loader:
...
train()
A resumed run continues rather than restarting from a good place, because Ravex restores everything around the weights too: optimizer state, LR scheduler, AMP loss scale, the torch, CUDA, Python and NumPy RNGs, and the position in the dataset. The test suite holds it to the strong form of that: a run killed at step 20 and resumed produces the same losses, step by step, and the same final weights as the run that was never interrupted.
preemption_handler=True catches SIGTERM and tries to write a final checkpoint
before the process is killed. Any other keyword argument to train_loop is a
configuration override, and an unknown name raises TypeError rather than
being ignored.
The decorator is the only way in. Up to 0.0.5 a .pth file in site-packages
attached Ravex to any process with a ravex.yaml above it; it was removed so
that nothing is ever checkpointed by code that does not say so. Importing
Ravex does nothing until a decorated function is called, and its patches on
PyTorch come off when that function returns or raises.
When "noticed on its own" is a guess, such as two models of which only one
trains, or an optimizer built before the function was entered, name it with
ravex.track(model, optimizer). The one moment a checkpoint is consistent,
the top of an iteration, Ravex takes from the DataLoader iterator or, in a
loop without one, from the first forward of the trained model after each
step; ravex.batch_boundary() hands it over by hand where neither is seen.
Configuration
ravex.yaml, at or above the working directory:
checkpoint_every: 500 # optimizer steps between checkpoints (default 100)
backend: moonclip # moonclip | torch_save
storage:
type: local # local | s3 | r2
path: ./checkpoints
keep_last: 5
max_steps: null # stop at this step however many times the process restarted
sharded_checkpoints: gather # gather | per_rank, for FSDP
Every option is also read from a RAVEX_* environment variable, which wins
over the file, and the keyword arguments to train_loop win over both. A
resume is the default (resume: true); RAVEX_ENABLED=0 turns Ravex off for
one run without touching the code.
Storage. Ravex decides when to save and what, and puts it back into the
live objects; Moonclip decides how the bytes are written and where, bucket
included. So storage says where the bucket is, and the credentials are never
read by Ravex or from the config file: Moonclip reads them from
MOONCLIP_S3_ACCESS_KEY / MOONCLIP_S3_SECRET_KEY or the usual AWS_* pair
(Moonclip's README).
More than one GPU or machine. DDP and FSDP resume on every rank. With FSDP,
gather writes one checkpoint that loads at any world size, bounded by what
rank 0 can hold; per_rank has each rank write its own shard, which is much
cheaper and resumes only at the same world size (reshard_on_resume handles a
different one after a restart). Across machines without a bucket or a shared
filesystem, replicate_every copies each rank's store to a peer on another
machine, so losing one machine costs at most that many checkpoints; with a
bucket, a rank that comes up with an empty disk pulls its store back. Ravex
also trains across slow links between distant nodes with an outer loop that
exchanges parameter differences every outer_inner_steps instead of gradients
every step.
The full option list, with the measurements behind the defaults: docs/configuration.md. How the patches, the step count and the resume work: docs/how-it-works.md.
Limits
- Under HuggingFace
Trainerand Lightning the state comes back exactly, but with shuffling and dropout on, the resumed run sees a different random draw, because the framework drives the dataloader and the RNG on its own schedule. Plain loops, DDP and FSDP replay exactly. - An
IterableDatasethas no index sampler, so its position cannot be replayed; everything else is still restored. - A sharded model gets no final checkpoint at exit, since collecting one is a collective and ranks stop being in lockstep at shutdown; the newest checkpoint is the last periodic one.
- A failed checkpoint is lost, logged, and tried again at the next one;
a failure inside Ravex never stops the training (
fallback_on_error).
What changed between versions is in the CHANGELOG.
Development
pip install -e ".[dev]"
pytest tests/unit
tests/unit runs in one process on any OS. tests/distributed and
integration/ start several processes, use torchrun or kill a process with
SIGKILL, and need Linux. The integration tests run in their own image, with
--init so that the SIGKILL they send is not a no-op:
docker build -f integration/Dockerfile -t ravex-integration .
docker run --rm --init ravex-integration
Licence
Apache-2.0 — GPU Zero
Metadata
Release files for ravex 0.10.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 | Provenance | |
|---|---|---|---|---|
| ravex-0.10.1.tar.gz | 414.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ravex-0.10.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 796.9 kB
Release files / ravex-0.10.1.tar.gz
| Download URL | ravex-0.10.1.tar.gz |
|---|---|
| Size | 414.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ffbf5fdcb066b2fc5d6bad0e78a209fdcd29d806e26f397851fde0bf73a5664f
|
|
BLAKE2b-256 checksum How to use checksums |
fcdd661d0ef88a9e1eedd458626a2c6fb3db20de59f0d297518e1c66f0afe246
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / ravex-0.10.1-py3-none-any.whl
| Download URL | ravex-0.10.1-py3-none-any.whl |
|---|---|
| Size | 382.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7395b7847267a00c1231086433fbe32d3960aa9e489ce8ef9959c21cd15c21f3
|
|
BLAKE2b-256 checksum How to use checksums |
ba87b49b3fd8a91604dd134ca48d9414e9160e4931026e52c5adc4a8f31d688c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Security for ravex 0.10.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.