Skip to main content

Tiny ML experiment tracking on Cloudflare R2 + D1

Project description

r2d1

Tiny ML experiment tracking on Cloudflare R2 + D1.

from r2d1 import Tracker, r2d1

tracker = Tracker.from_env()

job = tracker.start_job("mnist_dit")

for epoch in r2d1(range(10), job=job, checkpoint_every=1, keep_last=2):
    loss = train_step(...)

    epoch.d1(loss=float(loss), lr=float(lr))

    if epoch.should_checkpoint:
        epoch.r2({
            "checkpoint.pt": "ckpt/checkpoint.pt",
            "config.json": {"epoch": epoch.i},
        })

job.complete()

Mental model

epoch.d1({...})  -> small JSON metrics/metadata -> D1
epoch.r2({...})  -> files/artifacts/checkpoints -> R2

Aliases are included:

epoch.log(...)        # same as epoch.d1(...)
epoch.checkpoint(...) # same as epoch.r2(...)

The loop is intentionally lowercase like tqdm:

from r2d1 import r2d1

for epoch in r2d1(range(100), job=job):
    ...

Install locally

pip install -e .

Cloudflare credentials

Tracker.from_env() reads:

export R2D1_ACCOUNT_ID="..."
export R2D1_API_TOKEN="..."
export R2D1_D1_DATABASE_ID="..."
export R2D1_R2_BUCKET="..."
export R2D1_R2_ACCESS_KEY="..."
export R2D1_R2_SECRET_KEY="..."
# optional:
export R2D1_R2_ENDPOINT_URL="https://<account_id>.r2.cloudflarestorage.com"

Or construct directly:

tracker = Tracker(
    account_id="...",
    api_token="...",
    d1_database_id="...",
    r2_bucket="...",
    r2_access_key="...",
    r2_secret_key="...",
)

Checkpoint rotation: keep only last two

Use keep_last=2:

for epoch in r2d1(range(400), job=job, checkpoint_every=10, keep_last=2):
    if epoch.should_checkpoint:
        epoch.r2({"model.safetensors": Path("model.safetensors")})

R2 layout:

jobs/job_3/checkpoints/slot_0/
  manifest.json
  model.safetensors

jobs/job_3/checkpoints/slot_1/
  manifest.json
  model.safetensors

Epoch 0 writes slot_0, epoch 10 writes slot_1, epoch 20 overwrites slot_0, etc. D1 only points at a checkpoint after the files and manifest.json have been uploaded successfully.

D1 schema

r2d1 creates three tables automatically:

  • jobs: run lifecycle + latest checkpoint pointer
  • epochs: per-epoch metrics, with fixed columns plus metrics_json
  • checkpoints: committed checkpoint manifests

epoch.d1(...) stores both convenience columns and a full JSON payload:

epoch.d1({
    "loss": 0.123,
    "lr": 3e-4,
    "fid": 18.2,
    "gpu": "B300",
})

R2 inputs

epoch.r2(...) accepts:

  • Path objects — streamed to R2, preferred for large checkpoints
  • bytes / bytearray
  • str — existing file path if it exists, otherwise UTF-8 text
  • dict / list / JSON-ish objects — encoded as JSON
  • file-like objects — spooled to a temp file, then uploaded

Example:

epoch.r2({
    "model.safetensors": Path("ckpt/model.safetensors"),
    "config.json": {"hidden_size": 1152, "depth": 28},
    "notes.txt": "loss looked stable",
})

Resume

job = tracker.resume_job(3)
files, manifest = job.load_latest(include_manifest=True)

print(manifest["epoch"])
model_bytes = files["model.safetensors"]

load_latest() validates file SHA256 hashes against the manifest.

Optional serialization helpers

Core r2d1 does not own model serialization. It ships whatever you provide.

There is an optional r2d1.checkpoint module for small/simple PyTorch/JAX cases, but for real training runs prefer framework-native checkpoint files such as safetensors, Orbax, Flax serialization, torch.save, etc., then pass those file paths to epoch.r2(...).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

r2d1-0.1.4.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

r2d1-0.1.4-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file r2d1-0.1.4.tar.gz.

File metadata

  • Download URL: r2d1-0.1.4.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for r2d1-0.1.4.tar.gz
Algorithm Hash digest
SHA256 458c271284cf3dae6bc806819e983efcf584dd839759c6d48b601f8e5daaa47a
MD5 15989a7e75c246c880e1cdb3277323c0
BLAKE2b-256 7c34d9fd1141393d757565080476c14dca377d87577ba04bd1d62e2a0c5aed78

See more details on using hashes here.

Provenance

The following attestation bundles were made for r2d1-0.1.4.tar.gz:

Publisher: publish.yml on sparsetrace/r2d1

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file r2d1-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: r2d1-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 14.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for r2d1-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 80c2b1a29dd2869842784d83949aa5fad4c4e5f3491cf673a602b6f6d43e9495
MD5 63cbbe7de54be63ecbc3f18d5802c32c
BLAKE2b-256 3cf16a5b6d39dca668f46a0b274b78f189418be6498867bcf55e3a9f852188f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for r2d1-0.1.4-py3-none-any.whl:

Publisher: publish.yml on sparsetrace/r2d1

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page