Getting Started

This guide walks you through installing RUMUS, defining your first neural network, training it, and saving the results. By the end you will have a working multi-layer perceptron trained on synthetic data.

Installation

RUMUS is published on crates.io. Add it to an existing Cargo project with a single command:

terminal
bash
"token">-comment"># Add RUMUS to your project
"token">-function">cargo add rumus

Your First Model

Models in RUMUS are plain Rust structs annotated with the #[derive(Module)] proc macro. This automatically implements parameter collection, device transfer, and serialization for every field that is itself a module.

Below is a three-layer MLP that takes 784-dimensional inputs (e.g. flattened 28x28 images) and produces 10 class logits. Each hidden layer is followed by a ReLU activation.

src/main.rs
rust
use rumus::nn::{type">Module, type">Linear};
use rumus::type">Tensor;

"token-attribute">#[derive(type">Module)]
struct MLP {
    fc1: type">Linear,
    fc2: type">Linear,
    fc3: type">Linear,
}

impl MLP {
    fn new() -> type">Self {
        type">Self {
            fc1: type">Linear::new(784, 256),
            fc2: type">Linear::new(256, 128),
            fc3: type">Linear::new(128, 10),
        }
    }

    fn forward(&self, x: &type">Tensor) -> type">Tensor {
        let x = self.fc1.forward(x).relu();
        let x = self.fc2.forward(&x).relu();
        self.fc3.forward(&x)
    }
}

Key Concepts

  • Linear is a fully connected layer with learnable weights and bias.
  • #[derive(Module)] auto-generates parameters(), to_device(), and trait implementations so you never write boilerplate.
  • .relu() is called directly on a Tensor, returning a new Tensor with the computation graph attached for autograd.

Training

Training follows the familiar zero-grad, forward, loss, backward, step loop. RUMUS provides first-class optimizers (SGD, Adam, AdamW) and common loss functions (MSE, cross-entropy) out of the box.

src/main.rs
rust
use rumus::nn::{type">Module, type">Linear};
use rumus::optim::type">Adam;
use rumus::loss::cross_entropy_loss;
use rumus::type">Tensor;

fn main() {
    "token-comment">// Create dummy training data
    let inputs = type">Tensor::randn(&[64, 784]);   "token-comment">// batch of 64 images
    let targets = type">Tensor::randint(0, 10, &[64]); "token-comment">// 10-class labels

    "token-comment">// Instantiate the model and optimizer
    let model = MLP::new();
    let optimizer = type">Adam::new(model.parameters(), 1e-3);

    "token-comment">// Training loop
    for epoch in 0..100 {
        "token-comment">// Forward pass
        let predictions = model.forward(&inputs);
        let loss = cross_entropy_loss(&predictions, &targets);

        "token-comment">// Backward pass
        optimizer.zero_grad();
        loss.backward();
        optimizer.step();

        if epoch % 10 == 0 {
            println!("Epoch {epoch}: loss = {:.4}", loss.item());
        }
    }
}

What is happening here?

  1. Data creation -- we generate random inputs and integer labels. In a real project you would load a dataset.
  2. Optimizer -- Adam::new takes the model's parameters and a learning rate.
  3. Forward pass -- the model produces predictions, and cross_entropy_loss computes a scalar loss.
  4. Backward pass -- loss.backward() traverses the computation graph and fills in gradients for every parameter.
  5. Optimizer step -- optimizer.step() updates parameters using the computed gradients.

Saving & Loading

RUMUS uses the safetensors format for model serialization. It is fast, memory-mapped, and safe against arbitrary code execution -- a perfect fit for Rust's safety philosophy.

src/main.rs
rust
use rumus::serialization::{save_safetensors, load_safetensors};

"token-comment">// Save model weights to disk
save_safetensors(&model, "model.safetensors")
    .expect("Failed to save model");

println!("Model saved successfully.");

Loading weights back is just as straightforward. Create a new model instance and populate it from the file:

src/main.rs
rust
"token-comment">// Load weights back into a fresh model
let mut model = MLP::new();
load_safetensors(&mut model, "model.safetensors")
    .expect("Failed to load model");

println!("Model loaded. Ready for inference.");

What's Next?

You have built, trained, and saved your first RUMUS model. Dive deeper into the framework with these guides: