A machine learning and deep learning library written in pure Rust.
Read RustyML User Guide for detailed documentation and tutorials of RustyML.
RustyML is a machine learning and deep learning library, built end to end in Rust with no C or C++ dependencies. It covers the full workflow: data preprocessing, feature engineering, model training, and evaluation. It uses Rust's memory safety, safe concurrency, and zero-cost abstractions.
- Pure Rust, no FFI: memory-safe and portable, with nothing to link against.
- Parallelized by default: heavy kernels use Rayon for multi-threaded computation.
- Algorithm coverage: classical supervised and unsupervised learning, anomaly detection, and a neural-network framework with a sequential model and a graph model.
- Reproducible: a single
set_global_seedcall makes every randomized component on the calling thread deterministic. A per-componentrandom_statecovers the rest. - Model persistence: save and load trained models and network weights as compact binary, using Serde and postcard.
- Evaluation metrics: regression, classification (binary and multiclass), and clustering, matching scikit-learn conventions.
Add RustyML to your Cargo.toml:
[dependencies]
rustyml = "*"
ndarray = "0.17"To slim the build, opt out of the default and name what you need:
# Everything (ml, nn, utils, metrics, math)
rustyml = "*"
# Just the neural-network framework
rustyml = { version = "*", default-features = false, features = ["neural_network"] }
# Just the evaluation metrics
rustyml = { version = "*", default-features = false, features = ["metrics"] }
# Show training progress bars in the terminal
rustyml = { version = "*", features = ["show_progress"] }MSRV: Rust 1.89+ (edition 2024).
use rustyml::prelude::machine_learning::*;
use ndarray::array;
fn main() {
// Train a regularization-free linear regression model
let mut model = LinearRegression::new(true)
.with_solver(LeastSquaresSolver::GradientDescent { learning_rate: 0.01, max_iter: 1000, tol: 1e-6 }).unwrap();
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);
// Persist and reload the trained model
model.save_to_path("linear_regression.bin").unwrap();
let restored = LinearRegression::load_from_path("linear_regression.bin").unwrap();
}use rustyml::prelude::neural_network::*;
use ndarray::Array;
fn main() {
// 32 samples, 784 input features, 10 output classes
let x = Array::ones((32, 784)).into_dyn();
let y = Array::ones((32, 10)).into_dyn();
// The builder collects the layers, and `build` draws every weight from the input shape
let mut model = SequentialBuilder::new()
.add(Dense::new(128, Activation::ReLU).unwrap())
.add(Dense::new(64, Activation::ReLU).unwrap())
.add(Dense::new(10, Activation::Softmax { axis: -1 }).unwrap())
.build(&Shape::known(x.shape()))
.unwrap();
model.compile(
Adam::new(0.001, 0.9, 0.999, 1e-8, 0.0).unwrap(),
CategoricalCrossEntropy::new(false),
);
model.summary(); // print the architecture
// 1 loss value per epoch, each measured while that epoch ran, not after it
let history = model.fit(&x, &y, 10).unwrap();
println!("Per-epoch loss: {:?}", history.loss());
// Score the weights the model holds now: inference mode, updates nothing
println!("Loss after training: {}", model.evaluate(&x, &y).unwrap());
let predictions = model.predict(&x).unwrap();
println!("Predictions shape: {:?}", predictions.shape());
// Save the trained weights to a file
model.save_to_path("model.bin").unwrap();
}A sequential model gives every layer 1 input, and that input is the output of the layer before
it. GraphBuilder removes that limit. A node is 1 call of 1 layer on the outputs of other
nodes. A model can therefore hold several inlets, several outlets, a shared tower, or a
residual connection. The merge family joins the branches: Add, Subtract, Multiply,
Average, Maximum, Minimum, and Concatenate.
use rustyml::prelude::neural_network::*;
use ndarray::Array;
fn main() {
// 4 samples of 8 features, and 2 output values per sample
let x = Array::ones((4, 8)).into_dyn();
let y = Array::ones((4, 2)).into_dyn();
// A residual block: the input of the block reaches the sum and the hidden layer alike
let mut builder = GraphBuilder::new();
let input = builder.input(Shape::known(&[4, 8]));
let hidden = builder.add(Dense::new(8, Activation::ReLU).unwrap(), &[input]);
let sum = builder.add(Add::new(), &[input, hidden]);
let head = builder.add(Dense::new(2, Activation::Linear).unwrap(), &[sum]);
let mut model = builder.build(&[head]).unwrap();
model.compile(
SGD::new(0.01, 0.0, false, 0.0).unwrap(),
MeanSquaredError::new(),
);
// 1 tensor per inlet, and 1 target per outlet
model.fit(&[&x], &[&y], 10).unwrap();
let predictions = model.predict(&[&x]).unwrap();
println!("Predictions shape: {:?}", predictions[0].shape());
}use rustyml::metrics::*;
use ndarray::array;
fn main() {
// Arguments are always (y_true, y_pred)
// ConfusionMatrix::new takes hard 0.0/1.0 labels (new_with_labels covers other pairs)
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];
// The two arguments carry independent storage types, so an owned array and a view mix
let cm = ConfusionMatrix::new(&y_true, &y_pred.view());
println!("Accuracy: {:.3}", cm.accuracy());
println!("F1 score: {:.3}", cm.f1_score());
}See at docs.rs
The crate uses feature flags for modular compilation:
| Feature | Description |
|---|---|
machine_learning |
Classical ML algorithms (enables math) |
neural_network |
Neural-network framework (enables math) |
utils |
Data preprocessing and dataset splitting (enables math) |
metrics |
Evaluation metrics (enables math) |
math |
Numerical primitives (distances, matrix products, parallel reductions) |
full |
All of the above modules |
default |
full |
show_progress |
Render training/iteration progress bars in the terminal |
RustyML is under active development. The API is stabilizing, but breaking changes can still
appear in minor releases before 1.0.0.
Contributions are welcome. To help build the Rust ML library, you can:
- Open issues for bugs or feature requests
- Submit pull requests for improvements
- Share feedback on the API design
- Improve the documentation and examples
Please also review the Code of Conduct.
SomeB1oody (stanyin64@gmail.com)
The MIT License covers this project. See the LICENSE file for details.