rustyml 0.14.0

A high-performance machine learning & deep learning library in pure Rust, offering ML algorithms and neural network support
Documentation
# 1.1. What is RustyML

RustyML is a machine learning and deep learning library written entirely in Rust. It covers the full workflow a data-science project needs — data preprocessing, feature engineering, model training, and evaluation. It provides classical machine-learning estimators (linear models, decision trees, SVMs, clustering, dimensionality reduction, anomaly detection) as well as a Keras-style neural-network framework.

This guide documents version `0.14`. The API is stabilizing, but minor releases can still introduce breaking changes, so pin a concrete version in `Cargo.toml` for production rather than tracking `*`. The authoritative API reference is at [docs.rs/rustyml](https://docs.rs/rustyml), and the source at [github.com/SomeB1oody/RustyML](https://github.com/SomeB1oody/RustyML).

## 1.1.1. Pure Rust, end to end

RustyML contains no C or C++ code: no BLAS to link, no LAPACK, no CUDA. That makes it highly portable, spares you from configuring a complicated environment by hand, and keeps you from hitting inscrutable errors at build time — which suits both production and newcomers. Most of the code is written in safe Rust, so its memory safety is guaranteed.

For performance, matrix multiplication goes through the pure-Rust [`gemmkit`](https://crates.io/crates/gemmkit) crate (reaching `ndarray` via the zero-copy [`gemmkit-ndarray`](https://crates.io/crates/gemmkit-ndarray) adapter). It dispatches at run time to the widest SIMD the current CPU actually supports (AVX-512F, AVX2+FMA, NEON, wasm `simd128`, with a scalar fallback), and decides on its own whether a given product is worth threading and across how many workers — so you get excellent performance across very different hardware.

## 1.1.2. Parallelism

RustyML parallelizes its compute-heavy kernels with Rayon, but never blindly. Below a certain size the overhead of multithreading makes the parallel path slower than the serial one, so every kernel class has a calibrated size threshold and switches to the parallel path only once parallel is measurably faster. Those thresholds are not hardcoded constants: `rustyml::tuning` lets you override them at run time without a recompile, which matters most when you deploy the same binary to machines with very different core counts. See [Performance Tuning and Parallelism](../Chapter-07/7.3._Performance_Tuning_and_Parallelism.md) for the details.

What the design buys you:

- Parallel reductions are *deterministic*: the blocked fold sums in a fixed order no matter how many threads run it, so results do not drift as you scale cores.
- Performance is predictable: no garbage-collection pauses, no JIT warmup, and no global interpreter lock serializing your threads.
- Nearly every randomized component honors a global seed (see [Reproducibility and Random Seeds](../Chapter-07/7.1._Reproducibility_and_Random_Seeds.md)), so a run reproduces across machines. The dimensionality reducers' iterative eigensolvers are deliberately left out, because they converge to the same result whatever the seed is.

## 1.1.3. Features and modules

RustyML is split into five modules, each controlled by a Cargo feature (`prelude` is shared). Naming features lets you compile only the parts you use. `machine_learning`, `neural_network`, `utils`, and `metrics` all enable `math` automatically.

| Feature / module | What lives in it |
|---|---|
| `machine_learning` | Classical machine-learning estimators |
| `neural_network` | The `Sequential` model plus layers (`Dense`, convolution, pooling, recurrent, dropout, normalization), activations, optimizers (`SGD`, `Adam`, `AdamW`, `RMSprop`, `AdaGrad`), and losses |
| `utils` | Preprocessing (the `StandardScaler` family of scalers, label helpers such as `to_categorical`) and dataset splitting (`train_test_split`, `train_test_split_stratified`) |
| `metrics` | Evaluation metrics for regression, classification (`ConfusionMatrix`, ROC AUC, log loss, ...), and clustering (ARI, silhouette, ...) |
| `math` | Numeric computation and `gemmkit`-backed matrix products |

The `default` feature turns everything on. There is also a separate `show_progress` feature that draws training progress bars; see [Installation and Feature Flags](./1.2._Installation_and_Feature_Flags.md).

## 1.1.4. An API modeled on scikit-learn and Keras

Classical estimators follow scikit-learn, exposing methods like `fit` and `predict`; the neural network follows Keras's `Sequential` model with its `add` / `compile` / `fit` / `predict` flow — which makes it easier to pick up if you know the Python data-science ecosystem. What changes is that data is `ndarray` arrays rather than NumPy (see [Working with ndarray](./1.3._Working_with_ndarray.md)), and fallible calls return `Result` instead of raising exceptions.

Here is a classical machine-learning example; you can see the API shape follows scikit-learn:

```rust
use rustyml::prelude::machine_learning::*;
use ndarray::array;

fn main() {
    // new(fit_intercept); the default solver is the exact closed form
    let mut model = LinearRegression::new(true);

    let x = array![[1.0, 2.0], [2.0, 3.0], [3.0, 4.0]];
    let y = array![6.0, 9.0, 12.0];

    model.fit(&x, &y).unwrap();
    let predictions = model.predict(&x).unwrap();
    println!("predictions: {:?}", predictions);
}
```

And here is neural-network code, whose architecture follows Keras:

```rust
use rustyml::prelude::neural_network::*;
use ndarray::Array;

fn main() {
    // 4 samples, 8 input features, 1 output
    let x = Array::ones((4, 8)).into_dyn();
    let y = Array::ones((4, 1)).into_dyn();

    let mut model = Sequential::new();
    model
        .add(Dense::new(8, 16, Activation::ReLU).unwrap())
        .add(Dense::new(16, 1, Activation::Linear).unwrap())
        .compile(
            Adam::new(0.001, 0.9, 0.999, 1e-8, 0.0).unwrap(),
            MeanSquaredError::new(),
        );

    model.summary(); // prints the architecture, just like Keras
    model.fit(&x, &y, 5).unwrap();

    let predictions = model.predict(&x).unwrap();
    println!("prediction shape: {:?}", predictions.shape());
}
```

The metrics keep the same design as scikit-learn too (every metric takes its arguments in `(y_true, y_pred)` order):

```rust
use rustyml::metrics::*;
use ndarray::array;

fn main() {
    let y_true = array![1.0, 0.0, 0.0, 1.0, 1.0];
    let y_pred = array![1.0, 0.0, 1.0, 1.0, 0.0];

    let cm = ConfusionMatrix::new(&y_true, &y_pred);
    println!("accuracy: {:.3}", cm.accuracy());
    println!("f1 score: {:.3}", cm.f1_score());
}
```

Unlike Python, RustyML's error propagation wraps the result of a fallible call in `Result<T, Error>`, and you can `match` on it to handle each outcome separately (either it succeeded and gives you `T`, or it failed and gives you an `Error`). See [Error Handling](./1.6._Error_Handling.md).

Hyperparameters are validated at the point they are supplied, and an illegal value is rejected on the spot. Configuration uses the builder pattern: an estimator names its essential hyperparameters in `new`, then layers optional settings through chained `with_*` methods, each validating what it receives (for example `LinearRegression::new(true).with_regularization(..)?`).

## 1.1.5. What pure Rust buys you

A RustyML program compiles to a single self-contained binary. There is no extra toolchain to install and no complicated environment to configure. Trained classical models and neural-network weights serialize to binary through `save_to_path` / `load_from_path`; see [Model Persistence in Depth](../Chapter-07/7.2._Model_Persistence_in_Depth.md). And because there is no GC, no interpreter, and no warmup, latency is predictable.

## 1.1.6. Notes on scope

RustyML is CPU-only. There is no GPU or CUDA backend. The neural-network framework suits small-to-medium models and deep learning that sits close to classical ML; it is not for training large vision or language models. The classical `machine_learning` and `utils` estimators all take an `f64` feature matrix, but the element type of what `predict` gives back varies by model, see the table in [Working with ndarray](./1.3._Working_with_ndarray.md). The neural-network stack works in `f32`, and its tensor type is `Tensor = ArrayD<f32>`. The framework does not build a dynamic autodiff graph the way PyTorch does.