Sakura: SOTA training services for PyTorch DDP / Lightning / HuggingFace Trainer.
Project description
Sakura
SOTA training services for PyTorch DDP / Lightning / HuggingFace Trainer. Async eval, async checkpoint, mixed precision, torch.compile, ZeRO-1, all installable on a single runtime, all driving a Rust-backed QUIC transport.
Install • Quickstart • Architecture • Services • Adapters • Dispatchers • Migrating from v0.1.x
What is Sakura?
Sakura v1.0 is a standard library that sits on top of every PyTorch frontend (torch.distributed.DistributedDataParallel, lightning.Trainer, transformers.Trainer) and accelerates training via a small, explicit set of installable services:
Telemetry— JSON-line event sinkMixedPrecision— autocast policies + GradScaler for fp16ActivationCheckpoint— selectivetorch.utils.checkpointwrappingCompile—torch.compilewith on-disk cacheZeRO1— optimizer-state shardingAsyncEval— eval at epoch end, dispatched off the training threadAsyncCheckpoint— state-dict writes, dispatched off the training thread
Async services dispatch work to a sakura-worker subprocess over QUIC (loopback or LAN/WAN). The transport is a Rust crate (sakura-wire) exposed to Python via PyO3. Process isolation means the GIL never contends between training and eval/checkpoint work — a real constraint that thread-pool-based async patterns hit head-on.
Three framework adapters translate framework hooks into runtime events:
LightningAdapter— alightning.CallbackHFAdapter— atransformers.TrainerCallbackDDPAdapter— explicit hooks for rawtorch.distributedloops
You install services on a SakuraRuntime, attach an adapter to your training loop, run as usual.
Install
pip install sakura-ml
# or with framework integrations:
pip install 'sakura-ml[lightning,huggingface]'
From source:
git clone https://github.com/zakuro-ai/sakura && cd sakura
uv pip install maturin
maturin develop --release
Wheel packaging is being finalized — until then, the from-source path is the recommended install.
Quickstart
Lightning
import lightning as L
from sakura import SakuraRuntime
from sakura.adapters import LightningAdapter
from sakura.services import MixedPrecision, Compile, AsyncEval, AsyncCheckpoint
from sakura.dispatch import InThreadDispatcher # or LocalDispatcher() to spawn a worker
with SakuraRuntime() as rt:
rt.install(MixedPrecision(dtype="bf16"))
rt.install(Compile(mode="reduce-overhead"))
rt.install(AsyncEval(
eval_fn=lambda epoch, payload: {"val_loss": evaluate(model, val_loader)},
eval_payload={},
dispatcher=InThreadDispatcher(),
))
rt.install(AsyncCheckpoint(
dir="ckpt/", every="best", metric="val_loss",
dispatcher=InThreadDispatcher(),
state_provider=lambda: {k: v.cpu() for k, v in model.state_dict().items()},
))
trainer = L.Trainer(
max_epochs=10,
accelerator="auto",
callbacks=[LightningAdapter(rt)],
)
trainer.fit(model, train_loader)
HuggingFace Trainer
from transformers import Trainer
from sakura import SakuraRuntime
from sakura.adapters import HFAdapter
from sakura.services import MixedPrecision, AsyncEval
with SakuraRuntime() as rt:
rt.install(MixedPrecision(dtype="bf16"))
rt.install(AsyncEval(eval_fn=eval_fn, eval_payload=val_payload,
dispatcher=InThreadDispatcher()))
trainer = Trainer(model=model, args=hf_args, train_dataset=train_ds,
callbacks=[HFAdapter(rt)])
trainer.train()
Raw PyTorch DDP
import torch.distributed as dist
from sakura import SakuraRuntime
from sakura.adapters import DDPAdapter
from sakura.services import ZeRO1, AsyncEval
with SakuraRuntime() as rt:
rt.install(ZeRO1())
rt.install(AsyncEval(eval_fn=eval_fn, eval_payload=val_payload,
dispatcher=InThreadDispatcher()))
adapter = DDPAdapter(rt, rank=dist.get_rank(), world_size=dist.get_world_size())
adapter.on_train_begin(model, optimizer, train_loader)
for epoch in range(num_epochs):
adapter.on_epoch_begin(epoch)
for step, batch in enumerate(train_loader):
adapter.on_train_step_begin(model, batch, step)
loss = train_one_step(model, batch, optimizer)
adapter.on_optimizer_step(optimizer)
adapter.on_epoch_end(epoch, model, optimizer, metrics={"train_loss": loss})
adapter.on_train_end(model)
Out-of-process worker (auto-spawned)
LocalDispatcher auto-spawns a sakura-worker subprocess on first dispatch. The eval runs in a separate Python interpreter — the GIL never contends with the training loop:
from sakura.dispatch import LocalDispatcher
dispatcher = LocalDispatcher() # spawns localhost worker over QUIC
rt.install(AsyncEval(eval_fn=eval_fn, eval_payload=val_payload, dispatcher=dispatcher))
To target an existing worker on another host:
from sakura.dispatch import RemoteDispatcher
dispatcher = RemoteDispatcher(uri="quic://eval-host:4433", cert_der=cert_bytes)
Architecture
┌─── Training process (Python, GIL) ──────────────────────┐
│ framework loop (Lightning / HF / raw DDP) │
│ │ hook │
│ ▼ │
│ Adapter — translates hooks → typed events │
│ │ │
│ ▼ │
│ SakuraRuntime — event bus + service registry │
│ │ │
│ ├─→ in-process services (MixedPrecision, …) │
│ └─→ dispatching services (AsyncEval, AsyncCkpt) │
│ │ │
│ ▼ │
│ Dispatcher (Local | Remote | InThread) │
│ │ PyO3 → sakura-wire (Rust) │
│ ▼ QUIC │
└──────────────────│──────────────────────────────────────┘
│
┌──────────────────▼──────────────────────────────────────┐
│ sakura-worker subprocess (Python, separate GIL) │
│ QUIC server → HandlerRegistry → user callable │
└─────────────────────────────────────────────────────────┘
Five execution states cover every dispatching combination: in-thread (synchronous, for tests), in-process (single Python proc), localhost subprocess (default), remote subprocess (cluster), Zakuro-backed (existing infra). A typed event bus (OnTrainBegin, OnEpochEnd, etc.) carries rank and world_size so DDP-aware services branch on event.rank without each adapter doing the bookkeeping.
Services
| Service | Priority | Hooks consumed | What it does |
|---|---|---|---|
Telemetry |
0 | every event | JSON record sink (callable / file / stream) |
MixedPrecision |
10 | train_begin, optimizer_step | wraps forward in torch.autocast; GradScaler for fp16 |
ActivationCheckpoint |
15 | train_begin | wraps matching submodules with torch.utils.checkpoint |
Compile |
20 | train_begin | torch.compile with on-disk cache |
ZeRO1 |
30 | train_begin, optimizer_step | optimizer-state sharding (single-rank passthrough; multi-rank in progress) |
AsyncEval |
80 | epoch_end | dispatch eval to worker; lazy future drain |
AsyncCheckpoint |
85 | epoch_end | dispatch state-dict write; modes: epoch / N / best |
Lower priority runs earlier. Service exceptions are isolated — one service crashing emits an OnError event but doesn't block the others.
Adapters
| Adapter | Type | Use case |
|---|---|---|
LightningAdapter |
lightning.Callback |
Drop-in for lightning.Trainer |
HFAdapter |
transformers.TrainerCallback |
Drop-in for transformers.Trainer (>=4.38) |
DDPAdapter |
explicit hooks | Raw PyTorch DDP loops |
Dispatchers
| Dispatcher | URI | When |
|---|---|---|
InThreadDispatcher |
— | Tests / debug; runs synchronously |
LocalDispatcher |
auto | Default; auto-spawns localhost sakura-worker |
RemoteDispatcher |
quic://host:port |
Existing remote worker daemon |
ZakuroDispatcher |
— | Wraps zakuro.Compute for users with existing Zakuro infra |
Migrating from v0.1.x
v0.1.x submodules (sakura.lightning.SakuraTrainer, sakura.huggingface.SakuraHFCallback, sakura.ddp.DDPAsyncEvalCallback, sakura.tensorflow.*, sakura.ml.*) have been removed at v1.0.
Users on v0.1.x should pin sakura-ml<1.0 if they're not migrating. To migrate, see docs/migration-from-0.1.md.
Development
git clone https://github.com/zakuro-ai/sakura && cd sakura
uv venv && source .venv/bin/activate
uv pip install maturin pytest cloudpickle numpy torch lightning transformers
maturin develop --release
pytest tests/
Rust workspace: crates/sakura-wire/ — codec + protocol + QUIC transport + PyO3 bindings.
cargo test --workspace
cargo bench -p sakura-wire
License
BSD-3-Clause.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sakura_ml-1.0.0a1.tar.gz.
File metadata
- Download URL: sakura_ml-1.0.0a1.tar.gz
- Upload date:
- Size: 67.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc0dd9007441423b5c299a667eb34eec7eea45fb1a9835d9269ee90597499d87
|
|
| MD5 |
9bc01d7f0677e733106abcd5b00e46b8
|
|
| BLAKE2b-256 |
ed8fec8a9b0f6ba27a217a136a213b57a2fe56d9dc8f0ec012c859cda460a327
|
File details
Details for the file sakura_ml-1.0.0a1-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: sakura_ml-1.0.0a1-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c8880f45438391b31787b6e6cfb7ce7d28055249867284685b95fb319077ada
|
|
| MD5 |
465e8f6153edb1a9a0bef3c5c434422f
|
|
| BLAKE2b-256 |
7233491b260b68f126e713d71fcf4917440df5c6f7505c80a45deba81e234c80
|
File details
Details for the file sakura_ml-1.0.0a1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: sakura_ml-1.0.0a1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.7 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
173af9ea96944bb4fa7994878d6411df5009cd02a60e176b8445c57e2e76de75
|
|
| MD5 |
059b56543452708c6537c570ca2a5670
|
|
| BLAKE2b-256 |
28a36adaf7f5b46b238cd0701e51bd17f16410a5bf748cb75a3fc0da1c33f23a
|
File details
Details for the file sakura_ml-1.0.0a1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: sakura_ml-1.0.0a1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0567fabed0a8e8207601b64a63b405ae05816de67979d6588ff2d8ac85079beb
|
|
| MD5 |
a356fb6ccfed16a7017f156e46585b31
|
|
| BLAKE2b-256 |
14a832fdab7720e0a1dcf2f28afce4a82ef0a0e646ea2c883b35412c8c134106
|
File details
Details for the file sakura_ml-1.0.0a1-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: sakura_ml-1.0.0a1-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ff13bf1959c94f5372ff499a2a0a382112b183eeb9f986aa998b5f1ea75df88
|
|
| MD5 |
5f7ce51b0ff88a2c71aab9a30622be21
|
|
| BLAKE2b-256 |
fa883c76344f9a96f0dba54653e25a4448e50f083cca309e1cb03c08038972ed
|