Quick Start¶
Environment¶
Create the environment files:
Before starting Compose, replace HOST_DATA_ROOT in .env and optionally configure trusted
dotfiles. File mode 600 is optional but recommended when either env file contains secrets. Then
start the local dev container and run project setup:
For remote containers, provider images, data mounts, and environment variables, see Environment Setup.
Explore the Notebooks¶
Download the released normalized datasets to DATA_ROOT and the inference checkpoint to
outputs/checkpoints/:
Start the local Marimo editor:
Open http://localhost:2718. On a remote instance, use the SSH tunnel from
Environment Setup and open the same local URL.
The five notebook entrypoints follow the workflow from data to evaluation:
| Notebook | Use |
|---|---|
etl.py |
Inspect ingestion, transformations, resampling, and normalized data |
dataloader.py |
Inspect manifests, splits, temporal windows, and batches |
config.py |
Build and validate experiment configurations |
training.py |
Step through optimization and validation traces |
inference.py |
Compare checkpoints and multi-step rollouts |
The released Mamba-3 checkpoint in inference.py requires CUDA. These notebooks are intended for
interactive exploration rather than unattended long-running jobs.
Data Processing¶
The data flow is raw files -> ingested parquet -> normalized parquet. Interactive
runs write scratch outputs for inspection without replacing persisted stage data.
The public Pozzato source supports this full path. The released synthetic asset is
normalized data; its raw Parquet inputs and generation pipeline are not public here.
For large runs, place scratch_store on persistent storage with enough capacity for
concurrent task outputs rather than relying on container /tmp.
Add a Dataset¶
Follow the current pozzato_2022 dataset layout:
mapping.py: define dataset-specific raw aliases and canonical columns withMappingSpec.raw.py: implement a raw adapter withplan_raw_tasksandload_raw_task.config.py: defineDatasetSpec, ingest/normalize specs, andDATASET.registry.py: register the dataset id soget_datasetcan find it.
Raw adapters yield IngestBatch objects. Batch metadata must include the protocol
and the protocol task keys used for manifests and normalization tasks. If a raw
source omits optional declared columns, add null columns in the adapter before
yielding the batch; generic ingest alignment treats missing declared columns as
errors. The Pozzato adapter is the current example: it infers protocol/task
metadata from file paths, requires exactly one matching Excel sheet, and fills
missing declared raw columns with nulls before alignment.
Run Ingest¶
from pathlib import Path
from batgrad.data.datasets.registry import get_dataset
from batgrad.data.processing.raw import IngestStageConfig
from batgrad.storage.local import LocalDataProcessingStore
dataset = get_dataset("pozzato-2022")
store = LocalDataProcessingStore(Path("/data"), create=True)
dataset.ingest(
input_store=store,
output_store=store,
config=IngestStageConfig(n_jobs=-1),
)
This writes ingested parquet shards and an ingested manifest.
Run Normalize¶
from batgrad.data.processing.normalize import NormalizeStageConfig
dataset.normalize(
input_store=store,
output_store=store,
config=NormalizeStageConfig(n_jobs=-1),
)
This reads the ingested manifest and writes normalized parquet shards plus a
normalized manifest. Use dry_run=True to validate tasks without writing outputs;
use max_batch_rows to keep large tasks on the bounded processing path. Bounded
normalization requires bounded-capable resampling; for protocols using linear
resampling, keep tasks on the full-task path with max_batch_rows=None or a
large enough limit.
Interactive Runs¶
run = dataset.normalize_interactive(
input_store=store,
scratch_store=store,
config=NormalizeStageConfig(n_jobs=1),
protocols="cycling",
group_values={"cell id": "A1"},
)
manifest = run.manifest()
data = run.scan()
run.clean()
protocols filters protocols, group_values filters task keys such as cell or
cycle, and scratch_store receives temporary outputs.
Machine Learning¶
The ML layer reads normalized manifests. Complete ingestion and normalization or download the released assets above, then choose a configuration whose manifest revision and selected columns match the normalized data.
The bundled configurations provide useful starting points:
configs/ml_dry_run_cpu.jsonruns a short attention/FFN smoke test on CPU without writing run artifacts.configs/ml_dry_run_gpu.jsonruns a short Mamba smoke test on CUDA without writing run artifacts.configs/ml_baseline.jsonis the full CUDA/W&B baseline and writes logs and checkpoints.
Use notebooks/config.py to edit the full schema. Its scaling editor derives
one explicit rule per selected input or target column. Known battery columns start
with editable suggestions, but the saved JSON always contains the resolved numeric
rules and should be reviewed against normalized manifest statistics.
Set data.store_root in the selected configuration or ensure DATA_ROOT points
to the data store, then run:
uv run scripts/train.py --config configs/ml_dry_run_cpu.json
uv run scripts/train.py --config configs/ml_dry_run_gpu.json
uv run scripts/train.py --config configs/ml_baseline.json
The baseline logs online to the batgrad W&B project. Authenticate with uv run wandb login, or
select stdout, JSONL, or offline W&B in the configuration. Run the baseline on two GPUs with DDP:
OMP_NUM_THREADS=1 uv run torchrun --standalone --nproc-per-node=2 \
scripts/train.py --config configs/ml_baseline.json
For file-backed runs, train_from_config creates the configured
run.output_dir/run.name directory. If run.name is omitted, it uses a local
timestamp. A named directory that already exists is deleted before the run
starts.
<run-dir>/
config.json
logs/
metrics.jsonl
payloads.jsonl
checkpoints/
<run-id-or-name>/
latest.pt
best_<metric>.pt
final.pt
Only enabled logger and checkpoint outputs are created. See ML Configuration, ML Data Loading, ML Models, ML Training, and ML Inference.