skumyol/rustral

Rust

3

189 commits

updated Jul 10, 2026

See the code

README

Rustral

A Rust neural network framework for auditable, backend-agnostic NLP research

Rustral logo

Rust License Tests EMNLP 2026


What Is Rustral?

Rustral is a 24-crate Rust workspace for building, training, and deploying neural networks. It is designed around three commitments that are unusual in the deep learning framework landscape:

  1. No hidden global state. Every forward pass receives an explicit ForwardCtx carrying the backend, training/inference mode, run ID, optional shape policy, and optional operation profiler. There is no silent model.train() / model.eval() toggle, no global tensor registry, and no implicit mode switching.

  2. Backend-independent model definitions. Layers are written against the Backend and TensorOps traits. The same model code runs unchanged on a reference CPU backend (ndarray with SIMD), an optimized Candle backend (CUDA/Metal), and an experimental cross-platform WGPU backend (native WGSL compute shaders).

  3. Reproducibility by construction. Every benchmark, NLP training run, and LLM inference run emits a schema-validated JSON manifest recording machine metadata, git SHA, dataset checksums, hyperparameters, and raw timing distributions with 95% confidence intervals. These manifests are validated in CI.

Rustral is the subject of an EMNLP 2026 systems paper (docs/paper/emnlp_paper.tex) that presents the first systematic 6-framework cross-framework operator benchmark and proposes Cross-Backend Consistency Regularization as a training-time methodology for preventing silent implementation drift.

Who Is It For?

  • Students learning how networks work under the hood
  • Researchers who want reproducible, typed model code with auditable execution
  • Engineers experimenting with Rust-native ML pipelines and deployment

Key Results at a Glance

6-Framework CPU Operator Comparison

Mean wall-clock ms on identical workloads (AMD EPYC 7702P, 64-core). Best per row in bold.

WorkloadRustralCandlePyTorchJAXTensorFlowONNX
matmul 128×1280.1050.1453.3580.1820.5551.111
matmul 512×5125.6191.7164.5290.9361.7141.963
attention (d=64)0.0260.0240.0890.1030.4380.038
attention (d=256)0.4560.5630.1690.5871.1130.127

GPU Comparison (CUDA, RTX 2080 Ti)

WorkloadRustral CUDAPyTorch CUDARatio
matmul 128×1280.0400.0802.0×
attention (d=64)0.1100.2582.3×

On-Device Kernel Speedups (CPU SIMD)

OperationBeforeAfterSpeedup
LayerNorm (batch 1k)21.71 ms1.69 ms12.8×
CrossEntropyLoss1000+ ms460.5 ms2.2×
Parallel MHA200+ ms142.7 ms1.5×

NLP Reproducibility (deliberately minimal baselines)

TaskRustralPyTorchVariance
SST-2 accuracy (smoke)0.5092 ± 0.00000.4897 ± 0.0200Rustral: zero
WikiText-2 perplexity (smoke)16,182 ± 14921,516 ± 3,306PyTorch: 22× larger
SST-2 accuracy (paper-profile)0.765 ± 0.0080.706 ± 0.015Rustral: ~2× lower variance

LLM Inference

MetricCPUCUDA
GPT-2 first-token latency847 ms42 ms
GPT-2 tokens/sec4.258.3
KV-cache decode step0.027 ms
LLaMA golden parity vs HF✅ <2×10⁻³

Low wrapper cost on one matched path: Rustral's transformer pipeline matches raw Candle at 1.09 ms in the reported workload. This is evidence for that measured path, not a general no-overhead claim.

Operator-to-task transfer: 12.8× LayerNorm speedup becomes 1.41× at the NLP pipeline level because normalization is <10% of total FLOPs. Microbenchmark speedups systematically overstate end-to-end gains—a finding with implications for how systems papers should report performance.


Architecture

Rustral is organized as a workspace of 24 focused crates:

Backends (ndarray CPU, Candle CPU/CUDA/Metal, WGPU)
    ↓
Core (Backend trait, TensorOps, ForwardCtx, Module, Parameter)
    ↓
Differentiation (reverse-mode Tape, fused losses)
    ↓
Modeling (Linear, Conv2d, LSTM, Transformer, LLaMA, MoE, GPT-2)
    ↓
Training (SGD/Adam/AdamW, DataLoader, TapeTrainer)
    ↓
Infrastructure (SafeTensors I/O, HF Hub, GGUF, Distributed, Metrics)
    ↓
Deployment (HTTP inference server, model zoo, ONNX export)
CrateRole
rustral-coreBackend, TensorOps (20+ primitives), ForwardCtx, Parameter, Module, NamedParameters
rustral-ndarray-backendReference CPU backend with SIMD (wide crate) and Rayon parallelism
rustral-candle-backendOptimized CPU/CUDA/Metal backend via Candle
rustral-wgpu-backendExperimental cross-platform GPU via native WGSL compute shaders
rustral-autodiffReverse-mode Tape with explicit watching, fused losses, and operation profiling
rustral-nnLayers: Linear, Conv2d, LSTM, Transformer (encoder/decoder), LLaMA (RMS norm, RoPE, SwiGLU, GQA), MoE
rustral-llmGPT-2/LLaMA inference, KV-cache incremental decode, HuggingFace SafeTensors loading, CausalLm trait, greedy generation CLI
rustral-optimSGD, Adam, AdamW with NamedParameters visitor path and learning rate schedules
rustral-dataDataset / DataLoader with in-memory, streaming, and mmap backends
rustral-ioSafeTensors save/load, sharded meta state dicts, strict validation
rustral-runtimeTapeTrainer, inference pools, model I/O, NLP example orchestrator
rustral-symbolicDependency graphs, spans, optimized subword tokenizers
rustral-distributedSingle-process DP/TP/ZeRO simulation, ProcessGroup abstraction
rustral-hfHuggingFace Hub integration, snapshot pinning, local model scanning
rustral-ggufGGUF format header parsing
rustral-benchSchema-v2 JSON benchmark harness, 6-framework cross-comparison, Criterion microbenches
rustral-metricsJSONL/TensorBoard-style metrics writers
rustral-autotunerKernel config search with ci_mode, fast(), and persistent cache
rustral-tuiLive terminal dashboard with progress bars, loss sparklines, memory/leak monitoring
rustral-inference-serverAxum HTTP service: /health, /v1/infer, /metrics, Docker
rustral-model-zooCurated checkpoint registry with HF tensor-name mapping notes
rustral-cuda-backendStandalone CUDA backend (separate from Candle CUDA path)
rustral-metal-backendStandalone Metal backend (separate from Candle Metal path)
rustral-onnx-exportExperimental ONNX Linear exporter

The critical design invariant: model code depends only on the Backend and TensorOps traits, not on any concrete backend. Swap the backend constructor and the same model runs on CPU, CUDA, Metal, or WGPU.


The ForwardCtx Abstraction

The central design choice. Every forward pass receives:

pub struct ForwardCtx<'a, B: Backend> {
    backend: &'a B,
    mode: Mode,           // Train or Inference
    run_id: u64,          // stable identifier
    shape_policy: ShapePolicy,
    profiler: Option<OperationProfiler>,
}

This eliminates an entire class of bugs. In PyTorch, calling model.train() sets a global flag; forgetting to toggle it produces silent correctness errors. In Rustral, the mode is carried through the call graph, and every operation that behaves differently in training vs. inference receives the mode explicitly. You cannot accidentally run inference with training-mode dropout.


Quick Start (5 Minutes)

# Clone and build
git clone https://github.com/skumyol/rustral.git && cd rustral
cargo build --workspace

# Run tests (formats, clippy, full suite — 700+ tests, 0 failures)
./run_tests.sh

# First example: XOR classification (proves the network learns)
cargo run -p rustral-runtime --features training --example tape_xor_classification

# SST-2 sentiment classifier (quick smoke test)
cargo run --release -p rustral-runtime --features training --example sst2_classifier -- --quick

# WikiText-2 language model
cargo run --release -p rustral-runtime --features training --example wikitext2_lm -- --quick

# Benchmark harness (CPU)
python3 scripts/bench/run_all.py --suite rustral --suite candle --repeats 3

GPU Training

# CUDA (requires nvcc + CUDA toolkit ≥ 12.0)
cargo run --release -p rustral-runtime --features "training,cuda" \
  --example sst2_classifier -- --paper --d-model 256 --num-layers 4

# Force Candle CPU backend when CUDA JIT overhead dominates
RUSTRAL_FORCE_CPU=1 cargo run --release -p rustral-runtime --features "training,cuda" \
  --example sst2_classifier -- --paper

LLM Inference

# GPT-2 generation with metrics JSON
cargo run -p rustral-llm --features hf-tokenizers -- \
  generate --model gpt2 --prompt "The capital of France is" --max-new-tokens 32

HTTP Inference Server

cargo run -p rustral-runtime --features training --example save_linear_artifact -- tiny_linear.safetensors
cargo run -p rustral-inference-server -- \
  --artifact tiny_linear.safetensors --bind 127.0.0.1:8080 --in-features 1 --out-features 1 --bias
curl -s -X POST http://127.0.0.1:8080/v1/infer \
  -H 'content-type: application/json' -d '{"input":[[0.25]]}'

Backends

BackendHardwareBest ForStatus
rustral-ndarray-backendCPUReference, correctness baselinesStable
rustral-candle-backendCPU, CUDA, MetalProduction training, GPU benchmarksStable
rustral-wgpu-backendGPU (Vulkan/Metal/DX12)Experiments, inference prototypingExperimental
// Same model code, three backends
use rustral_ndarray_backend::CpuBackend;
use rustral_candle_backend::CandleBackend;
use rustral_wgpu_backend::WgpuBackend;

let reference  = run(&CpuBackend::default())?;
let optimized  = run(&CandleBackend::cpu())?;
// let on_gpu  = run(&CandleBackend::cuda(0)?)?;

Design Philosophy

Rustral favors explicit structure over framework magic.

User needRustral solution
Build a layer without boilerplateLinearBuilder / Conv2dConfig initialize backend-owned parameters
Run the same model on another backendModel code depends on Backend, not a concrete tensor library
Know whether a pass is training or inferenceForwardCtx carries Mode::Train or Mode::Inference explicitly
Compose larger models from smaller piecesModule gives each layer a typed forward contract
Inspect or replace internalsAutodiff, optimizers, runtime, data, backends are separate crates
Move toward deploymentRust binaries embed the same model logic used in experiments

Framework Comparison

StackBest atRustral advantage
PyTorchEcosystem, pretrained models, notebooksRust-native deployment, explicit context, auditable internals
JAXTransforms, compilation, acceleratorsSimpler explicit systems model for Rust applications
CandlePractical Rust tensor executionRustral can use Candle as a backend while adding typed modules, trainers, IO
BurnHigh-level Rust DL ergonomicsRustral stays small, inspectable, and backend-contract focused

EMNLP 2026 Submission

Rustral is the subject of a systems paper submitted to EMNLP 2026 (ARR May cycle). The paper:

  • Frames Rustral as a research instrument that makes system internals transparent and reproducible
  • Presents the first 6-framework cross-framework operator benchmark under a unified schema
  • Proposes Cross-Backend Consistency Regularization (CBCR) — training-time regularization against a frozen reference model
  • Demonstrates operator-to-task transfer analysis showing that microbenchmark speedups systematically overstate end-to-end gains

Development Status

  • Tests: 700+ passed, 0 failures across all crates (excluding experimental WGPU backend from CI)
  • WGPU backend: 23/23 correctness tests pass (post binding-index de-confliction)
  • LLaMA golden parity: Forward pass logits match HuggingFace Transformers within 2×10⁻³ — CI-automated
  • cargo fmt: Clean
  • cargo clippy -D warnings: Clean
  • Benchmarks: Schema-v2 JSON, CI-validated, 6-framework CPU + 2-framework GPU

Run locally:

./run_tests.sh
# or stricter:
cargo fmt --all -- --check && cargo clippy --workspace --all-targets -- -D warnings \
  && cargo test --workspace --exclude rustral-wgpu-backend

Building a Model

use rustral_core::{Backend, ForwardCtx, Mode, Module};
use rustral_nn::{Linear, LinearBuilder, Conv2d, Conv2dConfig};

struct MyModel<B: Backend> {
    conv1: Conv2d<B>,
    fc1: Linear<B>,
    fc2: Linear<B>,
}

impl<B: Backend> MyModel<B> {
    fn new(backend: &B) -> Self {
        Self {
            conv1: Conv2dConfig::new(32, 3, 3).build(backend),
            fc1: LinearBuilder::new(32 * 7 * 7, 128).build(backend),
            fc2: LinearBuilder::new(128, 10).build(backend),
        }
    }

    fn forward(&self, image: &B::Tensor, ctx: &mut ForwardCtx<B>) -> B::Tensor {
        let ops = ctx.backend().ops();
        let x = self.conv1.forward(image.clone(), ctx).unwrap();
        let x = ops.relu(&x).unwrap();
        // ... reshape, fc1, relu, fc2 ...
        x
    }
}

Backend Swap Without Rewriting

fn run<B: Backend>(backend: &B) -> rustral_core::Result<B::Tensor> {
    let model = TinyMlp::new(backend)?;
    let input = backend.tensor_from_vec(vec![0.0, 1.0], &[1, 2])?;
    let mut ctx = ForwardCtx::new(backend, Mode::Inference);
    model.forward(input, &mut ctx)
}

let reference = run(&CpuBackend::default())?;
let fast_cpu  = run(&CandleBackend::cpu())?;

Mixed Precision Training

use rustral_optim::{MixedPrecisionOptimizer, DType};

let optimizer = MixedPrecisionOptimizer::new(Adam::new(0.001))
    .with_dtype(DType::Float16)
    .with_loss_scale(1024.0);

The candle backend uses the candle-core library for highly optimized CPU execution, plus optional CUDA and Metal paths:

use rustral_candle_backend::CandleBackend;

let backend = CandleBackend::cpu();
// Or with CUDA (requires nvcc / CUDA toolkit):
// let backend = CandleBackend::cuda(0)?;
// Or with Metal on macOS:
// let backend = CandleBackend::metal(0)?;

On large linear layers, candle can be up to ~20x faster than the ndarray backend on CPU.

The benchmark crate also ships CUDA and Metal workload binaries:

cargo run --release -p rustral-bench --features cuda --bin rustral_workloads_cuda -- --repeats 5 --warmup 2
cargo run --release -p rustral-bench --features metal --bin rustral_workloads_metal -- --repeats 5 --warmup 2
# Linux + NVIDIA: CUDA backend tests + runtime (`training,cuda`) + bench JSON integration (`RUSTRAL_TEST_GPU=1`)
./scripts/run_gpu_tests.sh

Flash Attention

use rustral_nn::{FlashAttention, SelfAttentionConfig};

let config = SelfAttentionConfig::new(768, 12);
let flash_attn = FlashAttention::new(&backend, config, 42)?;

Mixture of Experts (MoE)

use rustral_nn::{ExpertLayer, MoEConfig};

let config = MoEConfig::new(512, 64, 2048, 2);
let moe = ExpertLayer::new(&backend, config, 42)?;

Training and NLP (rustral-runtime)

ExampleCommand
XOR classificationcargo run -p rustral-runtime --features training --example tape_xor_classification
Tape training democargo run -p rustral-runtime --features training --example tape_train_demo
SST-2 classifiercargo run --release -p rustral-runtime --features training --example sst2_classifier -- --quick
WikiText-2 LMcargo run --release -p rustral-runtime --features training --example wikitext2_lm -- --quick
Mixed precisioncargo run -p rustral-runtime --features training --example mixed_precision_training

Layers and Models (rustral-nn)

ExampleCommand
XORcargo run -p rustral-nn --example xor
MNISTcargo run -p rustral-nn --example mnist
BERT encodercargo run -p rustral-nn --example transformer_bert_encoder
GPT decodercargo run -p rustral-nn --example transformer_gpt_decoder
MoE trainingcargo run -p rustral-nn --example moe_training

Candle Backend

ExampleCommand
Benchmarkcargo run -p rustral-candle-backend --example benchmark

Documentation

DocumentWhat It Covers
ARCHITECTURE.mdCrate map, design invariants, backend capabilities
docs/master-plan.mdFeature roadmap, LLM bites, pre-submission quality gates
docs/concepts.mdTutorial and concept guide
docs/api-signatures.mdPublic API inventory
EVALUATION.mdSST-2 and WikiText-2 methodology, metrics, reproducibility
BENCHMARKS.mdBenchmark harness, schema v2, release snapshots
docs/paper/emnlp_paper.texEMNLP 2026 submission
docs/index.htmlSingle-page unified documentation
API Docscargo doc --open

Platform Notes

PlatformCPUCUDAMetalWGPU
Linux + NVIDIA✅ ndarray/Candle✅ Candle⚠️ Experimental
macOS✅ ndarray/Candle✅ Candle✅ Metal-native
Windows✅ ndarray/Candle✅ DX12-native

Contributing

Good first issues: add an example, improve documentation, add tests for edge cases, fix compiler warnings. See CONTRIBUTING.md.


License

MIT OR Apache-2.0 — you may use either.


Rustral draws ideas from PyTorch's eager execution, JAX's functional purity, and Rust's ownership model. It aims to stay transparent and hackable alongside crates like Candle and Burn.

Contributors

skumyol

177 commits

skumyol/rustral

Rust

3

189 commits

updated Jul 10, 2026

See the code

README

Rustral

A Rust neural network framework for auditable, backend-agnostic NLP research

Rustral logo

Rust License Tests EMNLP 2026


What Is Rustral?

Rustral is a 24-crate Rust workspace for building, training, and deploying neural networks. It is designed around three commitments that are unusual in the deep learning framework landscape:

  1. No hidden global state. Every forward pass receives an explicit ForwardCtx carrying the backend, training/inference mode, run ID, optional shape policy, and optional operation profiler. There is no silent model.train() / model.eval() toggle, no global tensor registry, and no implicit mode switching.

  2. Backend-independent model definitions. Layers are written against the Backend and TensorOps traits. The same model code runs unchanged on a reference CPU backend (ndarray with SIMD), an optimized Candle backend (CUDA/Metal), and an experimental cross-platform WGPU backend (native WGSL compute shaders).

  3. Reproducibility by construction. Every benchmark, NLP training run, and LLM inference run emits a schema-validated JSON manifest recording machine metadata, git SHA, dataset checksums, hyperparameters, and raw timing distributions with 95% confidence intervals. These manifests are validated in CI.

Rustral is the subject of an EMNLP 2026 systems paper (docs/paper/emnlp_paper.tex) that presents the first systematic 6-framework cross-framework operator benchmark and proposes Cross-Backend Consistency Regularization as a training-time methodology for preventing silent implementation drift.

Who Is It For?

  • Students learning how networks work under the hood
  • Researchers who want reproducible, typed model code with auditable execution
  • Engineers experimenting with Rust-native ML pipelines and deployment

Key Results at a Glance

6-Framework CPU Operator Comparison

Mean wall-clock ms on identical workloads (AMD EPYC 7702P, 64-core). Best per row in bold.

WorkloadRustralCandlePyTorchJAXTensorFlowONNX
matmul 128×1280.1050.1453.3580.1820.5551.111
matmul 512×5125.6191.7164.5290.9361.7141.963
attention (d=64)0.0260.0240.0890.1030.4380.038
attention (d=256)0.4560.5630.1690.5871.1130.127

GPU Comparison (CUDA, RTX 2080 Ti)

WorkloadRustral CUDAPyTorch CUDARatio
matmul 128×1280.0400.0802.0×
attention (d=64)0.1100.2582.3×

On-Device Kernel Speedups (CPU SIMD)

OperationBeforeAfterSpeedup
LayerNorm (batch 1k)21.71 ms1.69 ms12.8×
CrossEntropyLoss1000+ ms460.5 ms2.2×
Parallel MHA200+ ms142.7 ms1.5×

NLP Reproducibility (deliberately minimal baselines)

TaskRustralPyTorchVariance
SST-2 accuracy (smoke)0.5092 ± 0.00000.4897 ± 0.0200Rustral: zero
WikiText-2 perplexity (smoke)16,182 ± 14921,516 ± 3,306PyTorch: 22× larger
SST-2 accuracy (paper-profile)0.765 ± 0.0080.706 ± 0.015Rustral: ~2× lower variance

LLM Inference

MetricCPUCUDA
GPT-2 first-token latency847 ms42 ms
GPT-2 tokens/sec4.258.3
KV-cache decode step0.027 ms
LLaMA golden parity vs HF✅ <2×10⁻³

Low wrapper cost on one matched path: Rustral's transformer pipeline matches raw Candle at 1.09 ms in the reported workload. This is evidence for that measured path, not a general no-overhead claim.

Operator-to-task transfer: 12.8× LayerNorm speedup becomes 1.41× at the NLP pipeline level because normalization is <10% of total FLOPs. Microbenchmark speedups systematically overstate end-to-end gains—a finding with implications for how systems papers should report performance.


Architecture

Rustral is organized as a workspace of 24 focused crates:

Backends (ndarray CPU, Candle CPU/CUDA/Metal, WGPU)
    ↓
Core (Backend trait, TensorOps, ForwardCtx, Module, Parameter)
    ↓
Differentiation (reverse-mode Tape, fused losses)
    ↓
Modeling (Linear, Conv2d, LSTM, Transformer, LLaMA, MoE, GPT-2)
    ↓
Training (SGD/Adam/AdamW, DataLoader, TapeTrainer)
    ↓
Infrastructure (SafeTensors I/O, HF Hub, GGUF, Distributed, Metrics)
    ↓
Deployment (HTTP inference server, model zoo, ONNX export)
CrateRole
rustral-coreBackend, TensorOps (20+ primitives), ForwardCtx, Parameter, Module, NamedParameters
rustral-ndarray-backendReference CPU backend with SIMD (wide crate) and Rayon parallelism
rustral-candle-backendOptimized CPU/CUDA/Metal backend via Candle
rustral-wgpu-backendExperimental cross-platform GPU via native WGSL compute shaders
rustral-autodiffReverse-mode Tape with explicit watching, fused losses, and operation profiling
rustral-nnLayers: Linear, Conv2d, LSTM, Transformer (encoder/decoder), LLaMA (RMS norm, RoPE, SwiGLU, GQA), MoE
rustral-llmGPT-2/LLaMA inference, KV-cache incremental decode, HuggingFace SafeTensors loading, CausalLm trait, greedy generation CLI
rustral-optimSGD, Adam, AdamW with NamedParameters visitor path and learning rate schedules
rustral-dataDataset / DataLoader with in-memory, streaming, and mmap backends
rustral-ioSafeTensors save/load, sharded meta state dicts, strict validation
rustral-runtimeTapeTrainer, inference pools, model I/O, NLP example orchestrator
rustral-symbolicDependency graphs, spans, optimized subword tokenizers
rustral-distributedSingle-process DP/TP/ZeRO simulation, ProcessGroup abstraction
rustral-hfHuggingFace Hub integration, snapshot pinning, local model scanning
rustral-ggufGGUF format header parsing
rustral-benchSchema-v2 JSON benchmark harness, 6-framework cross-comparison, Criterion microbenches
rustral-metricsJSONL/TensorBoard-style metrics writers
rustral-autotunerKernel config search with ci_mode, fast(), and persistent cache
rustral-tuiLive terminal dashboard with progress bars, loss sparklines, memory/leak monitoring
rustral-inference-serverAxum HTTP service: /health, /v1/infer, /metrics, Docker
rustral-model-zooCurated checkpoint registry with HF tensor-name mapping notes
rustral-cuda-backendStandalone CUDA backend (separate from Candle CUDA path)
rustral-metal-backendStandalone Metal backend (separate from Candle Metal path)
rustral-onnx-exportExperimental ONNX Linear exporter

The critical design invariant: model code depends only on the Backend and TensorOps traits, not on any concrete backend. Swap the backend constructor and the same model runs on CPU, CUDA, Metal, or WGPU.


The ForwardCtx Abstraction

The central design choice. Every forward pass receives:

pub struct ForwardCtx<'a, B: Backend> {
    backend: &'a B,
    mode: Mode,           // Train or Inference
    run_id: u64,          // stable identifier
    shape_policy: ShapePolicy,
    profiler: Option<OperationProfiler>,
}

This eliminates an entire class of bugs. In PyTorch, calling model.train() sets a global flag; forgetting to toggle it produces silent correctness errors. In Rustral, the mode is carried through the call graph, and every operation that behaves differently in training vs. inference receives the mode explicitly. You cannot accidentally run inference with training-mode dropout.


Quick Start (5 Minutes)

# Clone and build
git clone https://github.com/skumyol/rustral.git && cd rustral
cargo build --workspace

# Run tests (formats, clippy, full suite — 700+ tests, 0 failures)
./run_tests.sh

# First example: XOR classification (proves the network learns)
cargo run -p rustral-runtime --features training --example tape_xor_classification

# SST-2 sentiment classifier (quick smoke test)
cargo run --release -p rustral-runtime --features training --example sst2_classifier -- --quick

# WikiText-2 language model
cargo run --release -p rustral-runtime --features training --example wikitext2_lm -- --quick

# Benchmark harness (CPU)
python3 scripts/bench/run_all.py --suite rustral --suite candle --repeats 3

GPU Training

# CUDA (requires nvcc + CUDA toolkit ≥ 12.0)
cargo run --release -p rustral-runtime --features "training,cuda" \
  --example sst2_classifier -- --paper --d-model 256 --num-layers 4

# Force Candle CPU backend when CUDA JIT overhead dominates
RUSTRAL_FORCE_CPU=1 cargo run --release -p rustral-runtime --features "training,cuda" \
  --example sst2_classifier -- --paper

LLM Inference

# GPT-2 generation with metrics JSON
cargo run -p rustral-llm --features hf-tokenizers -- \
  generate --model gpt2 --prompt "The capital of France is" --max-new-tokens 32

HTTP Inference Server

cargo run -p rustral-runtime --features training --example save_linear_artifact -- tiny_linear.safetensors
cargo run -p rustral-inference-server -- \
  --artifact tiny_linear.safetensors --bind 127.0.0.1:8080 --in-features 1 --out-features 1 --bias
curl -s -X POST http://127.0.0.1:8080/v1/infer \
  -H 'content-type: application/json' -d '{"input":[[0.25]]}'

Backends

BackendHardwareBest ForStatus
rustral-ndarray-backendCPUReference, correctness baselinesStable
rustral-candle-backendCPU, CUDA, MetalProduction training, GPU benchmarksStable
rustral-wgpu-backendGPU (Vulkan/Metal/DX12)Experiments, inference prototypingExperimental
// Same model code, three backends
use rustral_ndarray_backend::CpuBackend;
use rustral_candle_backend::CandleBackend;
use rustral_wgpu_backend::WgpuBackend;

let reference  = run(&CpuBackend::default())?;
let optimized  = run(&CandleBackend::cpu())?;
// let on_gpu  = run(&CandleBackend::cuda(0)?)?;

Design Philosophy

Rustral favors explicit structure over framework magic.

User needRustral solution
Build a layer without boilerplateLinearBuilder / Conv2dConfig initialize backend-owned parameters
Run the same model on another backendModel code depends on Backend, not a concrete tensor library
Know whether a pass is training or inferenceForwardCtx carries Mode::Train or Mode::Inference explicitly
Compose larger models from smaller piecesModule gives each layer a typed forward contract
Inspect or replace internalsAutodiff, optimizers, runtime, data, backends are separate crates
Move toward deploymentRust binaries embed the same model logic used in experiments

Framework Comparison

StackBest atRustral advantage
PyTorchEcosystem, pretrained models, notebooksRust-native deployment, explicit context, auditable internals
JAXTransforms, compilation, acceleratorsSimpler explicit systems model for Rust applications
CandlePractical Rust tensor executionRustral can use Candle as a backend while adding typed modules, trainers, IO
BurnHigh-level Rust DL ergonomicsRustral stays small, inspectable, and backend-contract focused

EMNLP 2026 Submission

Rustral is the subject of a systems paper submitted to EMNLP 2026 (ARR May cycle). The paper:

  • Frames Rustral as a research instrument that makes system internals transparent and reproducible
  • Presents the first 6-framework cross-framework operator benchmark under a unified schema
  • Proposes Cross-Backend Consistency Regularization (CBCR) — training-time regularization against a frozen reference model
  • Demonstrates operator-to-task transfer analysis showing that microbenchmark speedups systematically overstate end-to-end gains

Development Status

  • Tests: 700+ passed, 0 failures across all crates (excluding experimental WGPU backend from CI)
  • WGPU backend: 23/23 correctness tests pass (post binding-index de-confliction)
  • LLaMA golden parity: Forward pass logits match HuggingFace Transformers within 2×10⁻³ — CI-automated
  • cargo fmt: Clean
  • cargo clippy -D warnings: Clean
  • Benchmarks: Schema-v2 JSON, CI-validated, 6-framework CPU + 2-framework GPU

Run locally:

./run_tests.sh
# or stricter:
cargo fmt --all -- --check && cargo clippy --workspace --all-targets -- -D warnings \
  && cargo test --workspace --exclude rustral-wgpu-backend

Building a Model

use rustral_core::{Backend, ForwardCtx, Mode, Module};
use rustral_nn::{Linear, LinearBuilder, Conv2d, Conv2dConfig};

struct MyModel<B: Backend> {
    conv1: Conv2d<B>,
    fc1: Linear<B>,
    fc2: Linear<B>,
}

impl<B: Backend> MyModel<B> {
    fn new(backend: &B) -> Self {
        Self {
            conv1: Conv2dConfig::new(32, 3, 3).build(backend),
            fc1: LinearBuilder::new(32 * 7 * 7, 128).build(backend),
            fc2: LinearBuilder::new(128, 10).build(backend),
        }
    }

    fn forward(&self, image: &B::Tensor, ctx: &mut ForwardCtx<B>) -> B::Tensor {
        let ops = ctx.backend().ops();
        let x = self.conv1.forward(image.clone(), ctx).unwrap();
        let x = ops.relu(&x).unwrap();
        // ... reshape, fc1, relu, fc2 ...
        x
    }
}

Backend Swap Without Rewriting

fn run<B: Backend>(backend: &B) -> rustral_core::Result<B::Tensor> {
    let model = TinyMlp::new(backend)?;
    let input = backend.tensor_from_vec(vec![0.0, 1.0], &[1, 2])?;
    let mut ctx = ForwardCtx::new(backend, Mode::Inference);
    model.forward(input, &mut ctx)
}

let reference = run(&CpuBackend::default())?;
let fast_cpu  = run(&CandleBackend::cpu())?;

Mixed Precision Training

use rustral_optim::{MixedPrecisionOptimizer, DType};

let optimizer = MixedPrecisionOptimizer::new(Adam::new(0.001))
    .with_dtype(DType::Float16)
    .with_loss_scale(1024.0);

The candle backend uses the candle-core library for highly optimized CPU execution, plus optional CUDA and Metal paths:

use rustral_candle_backend::CandleBackend;

let backend = CandleBackend::cpu();
// Or with CUDA (requires nvcc / CUDA toolkit):
// let backend = CandleBackend::cuda(0)?;
// Or with Metal on macOS:
// let backend = CandleBackend::metal(0)?;

On large linear layers, candle can be up to ~20x faster than the ndarray backend on CPU.

The benchmark crate also ships CUDA and Metal workload binaries:

cargo run --release -p rustral-bench --features cuda --bin rustral_workloads_cuda -- --repeats 5 --warmup 2
cargo run --release -p rustral-bench --features metal --bin rustral_workloads_metal -- --repeats 5 --warmup 2
# Linux + NVIDIA: CUDA backend tests + runtime (`training,cuda`) + bench JSON integration (`RUSTRAL_TEST_GPU=1`)
./scripts/run_gpu_tests.sh

Flash Attention

use rustral_nn::{FlashAttention, SelfAttentionConfig};

let config = SelfAttentionConfig::new(768, 12);
let flash_attn = FlashAttention::new(&backend, config, 42)?;

Mixture of Experts (MoE)

use rustral_nn::{ExpertLayer, MoEConfig};

let config = MoEConfig::new(512, 64, 2048, 2);
let moe = ExpertLayer::new(&backend, config, 42)?;

Training and NLP (rustral-runtime)

ExampleCommand
XOR classificationcargo run -p rustral-runtime --features training --example tape_xor_classification
Tape training democargo run -p rustral-runtime --features training --example tape_train_demo
SST-2 classifiercargo run --release -p rustral-runtime --features training --example sst2_classifier -- --quick
WikiText-2 LMcargo run --release -p rustral-runtime --features training --example wikitext2_lm -- --quick
Mixed precisioncargo run -p rustral-runtime --features training --example mixed_precision_training

Layers and Models (rustral-nn)

ExampleCommand
XORcargo run -p rustral-nn --example xor
MNISTcargo run -p rustral-nn --example mnist
BERT encodercargo run -p rustral-nn --example transformer_bert_encoder
GPT decodercargo run -p rustral-nn --example transformer_gpt_decoder
MoE trainingcargo run -p rustral-nn --example moe_training

Candle Backend

ExampleCommand
Benchmarkcargo run -p rustral-candle-backend --example benchmark

Documentation

DocumentWhat It Covers
ARCHITECTURE.mdCrate map, design invariants, backend capabilities
docs/master-plan.mdFeature roadmap, LLM bites, pre-submission quality gates
docs/concepts.mdTutorial and concept guide
docs/api-signatures.mdPublic API inventory
EVALUATION.mdSST-2 and WikiText-2 methodology, metrics, reproducibility
BENCHMARKS.mdBenchmark harness, schema v2, release snapshots
docs/paper/emnlp_paper.texEMNLP 2026 submission
docs/index.htmlSingle-page unified documentation
API Docscargo doc --open

Platform Notes

PlatformCPUCUDAMetalWGPU
Linux + NVIDIA✅ ndarray/Candle✅ Candle⚠️ Experimental
macOS✅ ndarray/Candle✅ Candle✅ Metal-native
Windows✅ ndarray/Candle✅ DX12-native

Contributing

Good first issues: add an example, improve documentation, add tests for edge cases, fix compiler warnings. See CONTRIBUTING.md.


License

MIT OR Apache-2.0 — you may use either.


Rustral draws ideas from PyTorch's eager execution, JAX's functional purity, and Rust's ownership model. It aims to stay transparent and hackable alongside crates like Candle and Burn.

Contributors

skumyol

177 commits

Languages

Rust

81.9%

Python

8.4%

Shell

3.2%

TeX

2.8%

Cuda

1.2%