torch-vault
Embedded Rust engine for zero-copy PyTorch checkpoint management and SQL-driven dataset streaming using safetensors, SQLite WAL mode, and DuckDB OLAP predicate pushdown.
Core Guarantee: Replaces insecure pickle-based torch.save with memory-mapped safetensors binary files indexed inside atomic SQLite WAL transactions.
Installation
Installing the Python Package & CLI
pip install torch-vault
Building from Source (Rust & PyO3)
Building from source requires Python >= 3.10 and a Rust toolchain (cargo and rustc):
git clone https://github.com/ethqnol/torch-vault.git
cd torch-vault
pip install maturin
maturin develop --release
Quickstart
import torch
import torch.nn as nn
from torch_vault import Vault, Segment
model = nn.Linear(10, 2)
optimizer = torch.optim.Adam(model.parameters())
vault = Vault("./checkpoints")
# Save weight checkpoint ONLY IF val_loss improves, while continuously logging metrics to SQLite
ckpt_id = vault.save(
model,
optimizer,
metrics={"val_loss": 0.342, "accuracy": 0.912},
save_if_better="val_loss",
mode="min"
)
# Export SQLite metrics history directly to a Pandas DataFrame
df = vault.to_dataframe()
# Load best model weights automatically from SQLite index
best = vault.load(metric="val_loss", mode="min")
model.load_state_dict(best["model"])
CLI & Interactive WebApp UI Inspector
# Launch interactive browser WebApp inspector at http://127.0.0.1:8000/
torch-vault ui ./checkpoints --port 8000
# Print terminal table of all checkpoints and logged metrics
torch-vault list ./checkpoints
About & Architecture Deep-Dive
torch-vault replaces un-indexed, pickle-based PyTorch state dict saving with a compiled Rust engine linked to Python via PyO3 bindings.
Checkpoint Subsystem (safetensors + SQLite WAL)
Model weight tensors are serialized into binary safetensors format using zero-copy memory mapping (memmap2). Checkpoint metadata (epoch, step, metrics, tags) is stored in an embedded SQLite index database (vault_index.db) configured with Write-Ahead Logging (WAL) for concurrent read access during training.
Dataset & Streaming Subsystem (DuckDB + Arrow C Stream)
Dataset filtering executes directly on NVMe disk inside an embedded DuckDB instance before crossing into Python memory. Filtered record batches cross the PyO3 boundary via zero-copy C-ABI Arrow memory pointers (__arrow_c_stream__ PyCapsule) into PyTorch DataLoaders.
Architectural Comparison Matrix
| Dimension | Standard PyTorch / Python Data Loaders | torch-vault (Rust Core) |
|---|---|---|
| Checkpoint Security | Uses pickle (torch.save), vulnerable to arbitrary code execution. | Uses zero-copy safetensors binary format. Safe and mmap-backed. |
| Crash Resilience | Simple atomic file renames can leave orphan corrupted files. | Write operations run inside atomic SQLite WAL transactions. |
| Metric Indexing | Manually parse filenames or JSON files in Python loops. | Embedded SQLite index with json_extract() query support. |
| Conditional Saving | Custom Python logic to track prior loss and compare floats. | save_if_better="val_loss" records metrics continuously, writing weight files only on improvement. |
| Train/Val/Test Splitting | Requires manual index slicing or full dataset loading in RAM. | to_dataloader(split=(0.8, 0.1, 0.1), seed=42) checks splits BEFORE running row transforms. |
| Dataset Filtering | Loads full dataset into Python RAM or uses slow Pandas filters. | DuckDB SQL predicate pushdown runs in C++/Rust on disk. |
End-to-End Production Showcase (PyTorch LSTM Sentiment Classifier)
import torch
import torch.nn as nn
from torch_vault import Vault, Segment
from torch_vault.transforms import (
Compose, LabelEncoder, Lambda, MinMaxScaler, RenameKey, SelectKeys
)
class SentimentLSTM(nn.Module):
def __init__(self, vocab_size: int, embed_dim: int = 64, hidden_dim: int = 128):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
self.fc = nn.Linear(hidden_dim, 2)
def forward(self, x):
out, (hn, cn) = self.lstm(self.embedding(x))
return self.fc(hn[-1])
vocab = {"<pad>": 0, "<unk>": 1, "good": 2, "bad": 3, "great": 4}
def preprocess_sample(row: dict) -> dict:
tokens = [vocab.get(w, 1) for w in str(row["text"]).lower().split()[:50]]
tokens += [0] * (50 - len(tokens))
return {
"input_ids": torch.tensor(tokens, dtype=torch.long),
"target": torch.tensor(row["sentiment_score"], dtype=torch.long),
}
label_encoder = LabelEncoder(key="raw_label", classes=["negative", "positive"])
pipeline = Compose([
RenameKey(src="raw_label", dst="sentiment_score"),
label_encoder,
Lambda(preprocess_sample),
SelectKeys("input_ids", "target"),
])
train_loader, val_loader, test_loader = (
Segment("data/reviews.parquet")
.where("length(text) > 10")
.transform(pipeline)
.to_dataloader(batch_size=32, split=(0.8, 0.1, 0.1), seed=42)
)
model = SentimentLSTM(vocab_size=len(vocab) + 10)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()
vault = Vault("./sentiment_vault")
for epoch in range(1, 6):
model.train()
for batch in train_loader:
optimizer.zero_grad()
loss = criterion(model(batch["input_ids"]), batch["target"])
loss.backward()
optimizer.step()
# Evaluate validation loss
model.eval()
val_loss = sum(criterion(model(b["input_ids"]), b["target"]).item() for b in val_loader) / len(val_loader)
vault.save(
model=model,
optimizer=optimizer,
metrics={"val_loss": val_loss},
epoch=epoch,
save_if_better="val_loss",
mode="min"
)
best_weights = vault.load(metric="val_loss", mode="min")
model.load_state_dict(best_weights["model"])
Vault API Specification
Opens or creates a checkpoint vault directory. Initializes an embedded SQLite index (vault_index.db) in WAL mode with multi-experiment run_id tracking.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| dir_path | str | Required | Target directory path where vault_index.db and .safetensors files are stored. |
| run_id | Optional[str] | "default" | Experiment or architecture identifier for multi-run comparison. |
| overwrite | bool | False | If True, wipes pre-existing records matching run_id. If False and run_id exists, raises a ValueError to prevent accidental metric collision. |
Vault instance. Modifies filesystem by creating dir_path and initializing SQLite database.
Continuously records metric history into SQLite, and conditionally serializes model state dicts to binary .safetensors files on disk.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| model | Optional[nn.Module] | None | PyTorch model whose state dict is saved. Pass None for metrics-only logging. |
| optimizer | Optional[Optimizer] | None | Optional optimizer instance whose parameter states are saved. |
| metrics | Optional[Dict[str, float]] | None | Scalar metrics indexed in SQLite JSON column. |
| step | Optional[int] | None | Global training step counter. |
| epoch | Optional[int] | None | Current epoch number. |
| tags | Optional[List[str]] | None | Optional string tags for metadata filtering. |
| save_if_better | Optional[str] | None | Metric key to compare against prior saved weight checkpoints. |
| keep_top_k | Optional[int] | None | If specified, automatically prunes older .safetensors weight files on disk when checkpoint count exceeds keep_top_k, while preserving metric history in SQLite. |
| mode | "min" | "max" | "min" | Optimization direction ("min" for loss, "max" for accuracy). |
str checkpoint ID if .safetensors file was written to disk, or None if weight file save was skipped. Modifies SQLite database state in-place.
Lightweight helper that records scalar metrics directly into the SQLite index without passing a model instance or writing binary weight files.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| metrics | Dict[str, float] | Required | Dictionary of scalar metric names and float values. |
| step | Optional[int] | None | Global training step counter. |
| epoch | Optional[int] | None | Current epoch number. |
| tags | Optional[List[str]] | None | String tags for query filtering. |
str checkpoint ID of the inserted SQLite metric record. Modifies SQLite index in-place.
Exports SQLite index metadata and flattened scalar metrics into a Pandas DataFrame for analysis or visualization.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| query | Optional[str] | None | Optional SQL WHERE clause to filter exported records. |
pandas.DataFrame containing flattened metadata columns (read-only query; does not modify DB).
Reconstructs PyTorch state dict tensors from memory-mapped .safetensors files. Provide exactly one selector argument.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| checkpoint_id | Optional[str] | None | Exact UUID string of checkpoint to load. |
| query | Optional[str] | None | SQL WHERE query to select checkpoint. |
| metric | Optional[str] | None | Metric name to auto-select best checkpoint. |
| mode | "min" | "max" | "min" | Metric optimization direction. |
{"model": Dict[str, Tensor], "optimizer": Dict} (pure read operation).
Queries and returns all checkpoint records in SQLite ordered by creation timestamp.
List[Dict] of metadata records (read-only).
Executes an arbitrary SQL WHERE clause against SQLite index database.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| sql_where | str | Required | SQL predicate expression (e.g. "epoch >= 5 AND val_loss < 0.4"). |
List[Dict] matching the query (read-only).
Deletes the checkpoint record from SQLite index and removes its .safetensors weight file from disk.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| checkpoint_id | str | Required | UUID string of checkpoint to remove. |
None. Modifies database and deletes weight file from disk.
Queries SQLite for the single best metadata record for a metric without loading weight tensors.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| metric | str | Required | Metric name to evaluate. |
| mode | "min" | "max" | "min" | Optimization direction. |
Optional[Dict] metadata record (read-only).
Queries SQLite metrics history and generates styled publication-ready metric charts.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| metrics | Optional[List[str]] | None | List of metric keys to plot. Defaults to all scalar metrics. |
| x_axis | "epoch" | "step" | "created_at" | "epoch" | X-axis dimension. |
| kind | "line" | "bar" | "scatter" | "line" | Plot style type. |
| title | Optional[str] | None | Custom chart title. |
| dark_mode | bool | True | Use dark theme background styling. |
| output_path | Optional[str] | None | File path to save image(s). |
| separate_files | bool | False | If True, plots each metric on its own figure and saves to separate files. |
str (or List[str] if separate_files=True), or Matplotlib Figure object(s).
Segment API Specification
Initializes a dataset query builder backed by an in-memory DuckDB engine. Source can be a Parquet path (.parquet), CSV file (.csv, .tsv, .csv.gz), Hugging Face dataset name ("hf://stanfordnlp/imdb"), or a Hugging Face Dataset object.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| source | Union[str, Dataset] | Required | File path, CSV file, Hugging Face URI ("hf://..."), or HF Dataset instance. |
| split | str | "train" | Dataset split name if passing Hugging Face DatasetDict. |
Segment instance.
Ergonomic constructor that initializes a Segment directly from a Hugging Face dataset identifier or DatasetDict instance with flexible split combinations and slice support.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| dataset | Union[str, Dataset, DatasetDict] | Required | Hugging Face dataset identifier (e.g. "stanfordnlp/imdb") or loaded Dataset/DatasetDict. |
| split | Union[str, List[str]] | "train" (or all splits if None) | Dataset split identifier, slice ("train[:80%]"), string combination ("train+test"), or list of splits (["train", "test"]). |
Segment instance ready for SQL pushdown filtering.
Appends a SQL predicate for DuckDB pushdown. Predicates run directly on disk in C++/Rust before records reach Python memory.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| predicate | str | Required | SQL expression (e.g. "score > 0.8 AND split = 'train'"). |
Segment instance with the added predicate.
Registers a row-level Python callable fn(dict) -> dict to transform individual record dictionaries.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| fn | Callable[[Dict], Dict] | Required | Function taking sample dict and returning processed dict. |
Segment instance.
Registers a batch-level callable to transform an entire PyArrow RecordBatch at once for vectorized processing.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| fn | Callable[[RecordBatch], RecordBatch] | Required | Function processing PyArrow RecordBatch. |
Segment instance.
Wraps the segment in PyTorch DataLoader(s). Pass split=(0.8, 0.1, 0.1) or split=(0.8, 0.2) to create train/val/test DataLoader tuples.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| batch_size | int | 32 | Number of samples per batch. |
| num_workers | int | 0 | Subprocesses for data loading. |
| split | Optional[Tuple[float, ...]] | None | Split ratios tuple e.g. (0.8, 0.1, 0.1). Evaluated BEFORE transforms! |
| seed | int | 42 | Pseudo-random seed for deterministic split partitioning. |
DataLoader (if split=None) or a Tuple[DataLoader, ...].
Exports an Arrow C Stream Interface PyCapsule object ("arrow_array_stream") for zero-copy memory interchange with PyArrow or Polars.
PyCapsule memory pointer object.
Returns the constructed DuckDB SQL query string generated by the accumulated .where() predicates.
str SQL query string (read-only).
Transforms & Preprocessing Reference
Chains multiple row transform callables sequentially.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| transforms | List[Callable] | Required | List of transform callables. |
Compose instance.Wraps an arbitrary Python callable into a pipeline transform step.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| func | Callable[[Dict], Dict] | Required | Python function to execute on sample dict. |
| name | str | "lambda" | Step identifier name. |
Lambda instance.Filters a sample dictionary to retain only specified key names.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| *keys | str | Required | Positional string key names to retain. |
SelectKeys instance.Renames a sample dictionary key from src to dst.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| src | str | Required | Source key name. |
| dst | str | Required | Destination key name. |
RenameKey instance.Maps categorical string labels to integer class indices (0, 1, 2...). Support .fit(samples).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| key | str | Required | Dictionary field key to encode. |
| classes | Optional[List[Any]] | None | Explicit class ordering list. |
LabelEncoder instance (modifies mapping state on .fit()).Standardizes numeric fields to zero mean and unit variance: (x - mean) / std. Supports .fit(samples).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| keys | List[str] | Required | Numeric field keys to scale. |
StandardScaler instance.Scales numeric fields to a specified range [a, b]. Supports .fit(samples).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| keys | List[str] | Required | Numeric field keys to scale. |
| feature_range | Tuple[float, float] | (0.0, 1.0) | Target min and max range bounds. |
MinMaxScaler instance.