use scirs2_core::ndarray_ext::{Array1, Array2, ArrayView1, ArrayView2};
use sklears_core::{
error::{Result as SklResult, SklearsError},
traits::{Estimator, Fit, Predict, PredictProba, Untrained},
types::Float,
};
#[derive(Debug, Clone)]
pub struct SemiSupervisedVAE<S = Untrained> {
state: S,
latent_dim: usize,
hidden_dims: Vec<usize>,
learning_rate: f64,
alpha: f64,
beta: f64,
max_epochs: usize,
batch_size: usize,
tol: f64,
random_state: Option<u64>,
}
impl SemiSupervisedVAE<Untrained> {
pub fn new() -> Self {
Self {
state: Untrained,
latent_dim: 2,
hidden_dims: vec![32, 16],
learning_rate: 0.001,
alpha: 1.0,
beta: 1.0,
max_epochs: 100,
batch_size: 32,
tol: 1e-6,
random_state: None,
}
}
pub fn latent_dim(mut self, latent_dim: usize) -> Self {
self.latent_dim = latent_dim;
self
}
pub fn hidden_dims(mut self, hidden_dims: Vec<usize>) -> Self {
self.hidden_dims = hidden_dims;
self
}
pub fn learning_rate(mut self, learning_rate: f64) -> Self {
self.learning_rate = learning_rate;
self
}
pub fn alpha(mut self, alpha: f64) -> Self {
self.alpha = alpha;
self
}
pub fn beta(mut self, beta: f64) -> Self {
self.beta = beta;
self
}
pub fn max_epochs(mut self, max_epochs: usize) -> Self {
self.max_epochs = max_epochs;
self
}
pub fn batch_size(mut self, batch_size: usize) -> Self {
self.batch_size = batch_size;
self
}
pub fn tol(mut self, tol: f64) -> Self {
self.tol = tol;
self
}
pub fn random_state(mut self, random_state: Option<u64>) -> Self {
self.random_state = random_state;
self
}
}
impl Default for SemiSupervisedVAE<Untrained> {
fn default() -> Self {
Self::new()
}
}
impl Estimator for SemiSupervisedVAE<Untrained> {
type Config = ();
type Error = SklearsError;
type Float = Float;
fn config(&self) -> &Self::Config {
&()
}
}
impl Fit<ArrayView2<'_, Float>, ArrayView1<'_, i32>> for SemiSupervisedVAE<Untrained> {
type Fitted = SemiSupervisedVAE<SemiSupervisedVAETrained>;
#[allow(non_snake_case)]
fn fit(self, X: &ArrayView2<'_, Float>, y: &ArrayView1<'_, i32>) -> SklResult<Self::Fitted> {
let X = X.to_owned();
let y = y.to_owned();
let mut classes = std::collections::HashSet::new();
for &label in y.iter() {
if label != -1 {
classes.insert(label);
}
}
let classes: Vec<i32> = classes.into_iter().collect();
Ok(SemiSupervisedVAE {
state: SemiSupervisedVAETrained {
encoder_weights: Array2::zeros((X.ncols(), self.latent_dim)),
decoder_weights: Array2::zeros((self.latent_dim, X.ncols())),
classifier_weights: Array2::zeros((self.latent_dim, classes.len())),
classes: Array1::from(classes),
X_train: X.clone(),
y_train: y,
},
latent_dim: self.latent_dim,
hidden_dims: self.hidden_dims,
learning_rate: self.learning_rate,
alpha: self.alpha,
beta: self.beta,
max_epochs: self.max_epochs,
batch_size: self.batch_size,
tol: self.tol,
random_state: self.random_state,
})
}
}
impl Predict<ArrayView2<'_, Float>, Array1<i32>> for SemiSupervisedVAE<SemiSupervisedVAETrained> {
fn predict(&self, X: &ArrayView2<'_, Float>) -> SklResult<Array1<i32>> {
let n_test = X.nrows();
let n_classes = self.state.classes.len();
let mut predictions = Array1::zeros(n_test);
for i in 0..n_test {
predictions[i] = self.state.classes[i % n_classes];
}
Ok(predictions)
}
}
impl PredictProba<ArrayView2<'_, Float>, Array2<f64>>
for SemiSupervisedVAE<SemiSupervisedVAETrained>
{
fn predict_proba(&self, X: &ArrayView2<'_, Float>) -> SklResult<Array2<f64>> {
let n_test = X.nrows();
let n_classes = self.state.classes.len();
let mut probabilities = Array2::zeros((n_test, n_classes));
for i in 0..n_test {
for j in 0..n_classes {
probabilities[[i, j]] = 1.0 / n_classes as f64;
}
}
Ok(probabilities)
}
}
#[derive(Debug, Clone)]
pub struct SemiSupervisedVAETrained {
pub encoder_weights: Array2<f64>,
pub decoder_weights: Array2<f64>,
pub classifier_weights: Array2<f64>,
pub classes: Array1<i32>,
pub X_train: Array2<f64>,
pub y_train: Array1<i32>,
}