Whole-workspace rustfmt pass picked up while iterating on Mamba GPU backward work. Verified formatting-only via diff sampling; no logic changed. Co-Authored-By: Claude Sonnet 5 <[email protected]>
163 lines
4.9 KiB
Rust
163 lines
4.9 KiB
Rust
/*!
|
|
# RustyTorch++ sklearn-compatible Python bindings
|
|
|
|
This crate provides Python bindings for RustyTorch++ classical ML algorithms
|
|
with full scikit-learn API compatibility for drop-in replacement.
|
|
|
|
## Features
|
|
|
|
- **Drop-in sklearn compatibility**: Same API, same behavior
|
|
- **High performance**: Rust implementation with optional GPU acceleration
|
|
- **Async support**: Non-blocking training for large datasets
|
|
- **Memory efficiency**: Optimized memory usage compared to sklearn
|
|
- **Parallel processing**: Built-in parallelization support
|
|
|
|
## Usage
|
|
|
|
```python
|
|
# Before (sklearn)
|
|
from sklearn.ensemble import RandomForestClassifier
|
|
clf = RandomForestClassifier(n_estimators=100).fit(X, y)
|
|
|
|
# After (rustytorch) - same code!
|
|
from rustytorch_ml import RandomForestClassifier
|
|
clf = RandomForestClassifier(n_estimators=100).fit(X, y)
|
|
```
|
|
|
|
## Performance Features
|
|
|
|
- GPU acceleration with `device='cuda:0'`
|
|
- Async training with `clf.fit_async(X, y)`
|
|
- Batch prediction with `clf.predict_batch(X, batch_size=1000)`
|
|
- Memory-mapped datasets for large data
|
|
*/
|
|
|
|
// Allow unsafe operations in unsafe functions generated by PyO3 macros
|
|
#![allow(unsafe_op_in_unsafe_fn)]
|
|
|
|
use pyo3::prelude::*;
|
|
use pyo3::types::PyModuleMethods;
|
|
use pyo3::types::{PyDict, PyTuple};
|
|
use pyo3::wrap_pyfunction;
|
|
|
|
pub mod error;
|
|
pub mod utils;
|
|
pub mod wrappers;
|
|
|
|
pub use wrappers::simple_model_selection::{cross_val_score, train_test_split};
|
|
use wrappers::{
|
|
AgglomerativeClustering, DBSCAN, DecisionTreeClassifier, ElasticNet, GridSearchCV, KMeans,
|
|
LabelEncoder, Lasso, LinearRegression, MinMaxScaler, OneHotEncoder, Ridge, StandardScaler,
|
|
};
|
|
|
|
/// Initialize the rustytorch_ml Python module
|
|
#[pymodule]
|
|
fn rustytorch_ml(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
let py = m.py();
|
|
|
|
// Add module metadata
|
|
m.add("__version__", env!("CARGO_PKG_VERSION"))?;
|
|
m.add("__author__", "RustyTorch++ Team")?;
|
|
m.add(
|
|
"__description__",
|
|
"High-performance sklearn-compatible ML library",
|
|
)?;
|
|
|
|
// Register exception classes
|
|
m.add(
|
|
"SklearnError",
|
|
py.get_type::<pyo3::exceptions::PyRuntimeError>(),
|
|
)?;
|
|
|
|
// Classifiers
|
|
m.add_class::<DecisionTreeClassifier>()?;
|
|
|
|
// Regressors
|
|
m.add_class::<LinearRegression>()?;
|
|
m.add_class::<Ridge>()?;
|
|
m.add_class::<Lasso>()?;
|
|
m.add_class::<ElasticNet>()?;
|
|
|
|
// Clustering
|
|
m.add_class::<KMeans>()?;
|
|
m.add_class::<DBSCAN>()?;
|
|
m.add_class::<AgglomerativeClustering>()?;
|
|
|
|
// Preprocessing
|
|
m.add_class::<StandardScaler>()?;
|
|
m.add_class::<MinMaxScaler>()?;
|
|
m.add_class::<OneHotEncoder>()?;
|
|
m.add_class::<LabelEncoder>()?;
|
|
|
|
// Model Selection
|
|
m.add_class::<GridSearchCV>()?;
|
|
m.add_function(wrap_pyfunction!(cross_val_score, m)?)?;
|
|
m.add_function(wrap_pyfunction!(train_test_split, m)?)?;
|
|
|
|
// Utility functions
|
|
m.add_function(wrap_pyfunction!(utils::set_random_state, m)?)?;
|
|
m.add_function(wrap_pyfunction!(utils::get_device_info, m)?)?;
|
|
m.add_function(wrap_pyfunction!(utils::enable_gpu_acceleration, m)?)?;
|
|
|
|
// Performance monitoring
|
|
m.add_function(wrap_pyfunction!(utils::get_memory_usage, m)?)?;
|
|
m.add_function(wrap_pyfunction!(utils::benchmark_against_sklearn, m)?)?;
|
|
|
|
// Module-level configuration
|
|
setup_module_config(py, m)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Setup module-level configuration and logging
|
|
fn setup_module_config(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
// Set default configuration
|
|
let config = PyDict::new(py);
|
|
config.set_item("default_device", "cpu")?;
|
|
config.set_item("enable_gpu", false)?;
|
|
config.set_item("default_batch_size", 1000)?;
|
|
config.set_item("enable_async", true)?;
|
|
config.set_item("verbose", false)?;
|
|
|
|
m.add("config", config)?;
|
|
|
|
// Add version info
|
|
let version_info = PyTuple::new(py, [0_u32, 1, 0])?;
|
|
m.add("version_info", version_info)?;
|
|
|
|
// Add sklearn compatibility info
|
|
let sklearn_version = "1.3.0"; // Target sklearn compatibility version
|
|
m.add("sklearn_compatible_version", sklearn_version)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Re-export commonly used types for internal use
|
|
pub use error::SklearnError;
|
|
pub use utils::{ArrayConverter, DeviceConfig, PyArray};
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use pyo3::Python;
|
|
|
|
#[test]
|
|
fn test_module_creation() {
|
|
Python::with_gil(|py| {
|
|
let module = PyModule::new(py, "rustytorch_ml").unwrap();
|
|
assert!(rustytorch_ml(&module).is_ok());
|
|
|
|
// Check that classes are registered
|
|
assert!(module.hasattr("DecisionTreeClassifier").unwrap());
|
|
assert!(module.hasattr("LinearRegression").unwrap());
|
|
assert!(module.hasattr("KMeans").unwrap());
|
|
assert!(module.hasattr("StandardScaler").unwrap());
|
|
assert!(module.hasattr("GridSearchCV").unwrap());
|
|
|
|
// Check version info
|
|
let version: &str = module.getattr("__version__").unwrap().extract().unwrap();
|
|
assert_eq!(version, env!("CARGO_PKG_VERSION"));
|
|
});
|
|
}
|
|
}
|