Past where
scikit-learn stops.
Export to one portable ONNX artifact, serve a drift-monitored endpoint, version every model with its lineage, and — the framework pointed at itself — let AutoML search for the best deployable pipeline.
ONNX in and out.
With onnx, any model — or a whole pipeline — exports to one .onnx file. Whole-pipeline export folds leading affine scalers into the estimator's graph: raw features in, predictions out. InferenceModel::load runs any ONNX file back through tract.
let mut pipe = Pipeline::new() .step("scale", StandardScaler::new()) .estimator("lr", LinearRegression::new()); pipe.fit(&train)?; let native = pipe.predict(&probe)?; pipe.export_onnx("pipeline.onnx")?; // scaler + model, one graph let model = InferenceModel::load("pipeline.onnx")?; let via_onnx = model.predict(&probe)?; // matches `native`
Linear/affine/pipeline graphs run inside tract for a full round-trip. A random forest exports to a valid ONNX-ML tree-ensemble artifact for external runtimes (onnxruntime); tract implements NN ops, not the ONNX-ML tree ops.
cargo run --example portability --features "smartcore-backend onnx"
Registry, drift, serving.
The registry versions the ONNX artifact (content-addressed, with a reference distribution and movable tags); monitor watches the prediction stream for PSI drift; serve exposes a validated endpoint that feeds the monitor.
let reg = Registry::local("./models"); let v1 = reg.register("demand", &model, Metadata { metrics: vec![("r2".into(), 1.0)], reference: reference.clone(), // the distribution drift watches against note: "baseline".into(), })?; reg.tag("demand", &v1.id, "prod")?; let reverted = reg.rollback("demand", "prod")?; // revert in one line // serve the prod artifact, watching for drift on every request Server::from_onnx(reg.onnx_path("demand", "prod")?)? .route("/predict") .with_monitor(DriftMonitor::psi(&reference)?) .serve("0.0.0.0:8080").await?; // POST /predict, GET /metrics
cargo run --example operations --features "onnx registry monitor serve"
Server runs linear / NN ONNX graphs through tract, and evaluates ONNX-ML tree ensembles (a forest) with a small native interpreter — so a model exported by Millwright always serves in Millwright, and the artifact stays portable to any ONNX runtime.Time series & out-of-core.
Same contract, different data shapes — each gets its own trait. These two crates pin ndarray 0.15 while the rest of the stack uses 0.16; Cargo links both and converts only inside the adapters.
// time series (feature = "timeseries") let mut arima = AutoArima::new().max_p(3).max_q(3); arima.fit(&series)?; // &[f64] let forecast = arima.forecast(6)?; // six steps ahead // out-of-core (feature = "incremental") — never holds the whole set in memory let mut model = IncrementalLinear::with_rate(0.05, 0.0); for batch in batches { model.partial_fit(&batch)?; // one batch at a time }
cargo run --example specialized --features "timeseries incremental"
AutoML — the framework, pointed at itself.
Profiling, preprocessing, CV, search, and ensembling are exactly what an AutoML engine needs — so AutoML is not a bolt-on, it is the framework orchestrating its own parts. Point it at data and a budget; get a leaderboard and the best deployable model.
let result = AutoML::classifier() // or ::regressor() .budget(Budget::trials(20)) // or Budget::minutes(10) .metric(Metric::F1) .cv(StratifiedKFold::new(5)) .seed(0) .fit(&train)?; println!("{}", result.leaderboard()); result.export_onnx("model.onnx")?; // deployable — unlike a TPOT object
cargo run --example automl --features "automl onnx"