use rand::Rng;
use rustorch::nn::loss::mse_loss;
use rustorch::nn::Linear;
use rustorch::optim::{Optimizer, SGD};
use rustorch::prelude::*;
fn generate_data(n_samples: usize, n_features: usize) -> (Vec<f32>, Vec<f32>) {
let mut rng = rand::thread_rng();
let x_data: Vec<f32> = (0..n_samples * n_features)
.map(|_| rng.gen_range(-1.0..1.0))
.collect();
let true_weights: Vec<f32> = (0..n_features).map(|_| rng.gen_range(-1.0..1.0)).collect();
let mut y_data = Vec::with_capacity(n_samples);
for i in 0..n_samples {
let mut y = 0.0;
for j in 0..n_features {
y += x_data[i * n_features + j] * true_weights[j];
}
y += rng.gen_range(-0.1..0.1);
y_data.push(y);
}
(x_data, y_data)
}
fn main() {
let n_samples = 100;
let n_features = 3;
let (x_data, y_data) = generate_data(n_samples, n_features);
let x_tensor = Tensor::from_vec(x_data, vec![n_samples, n_features]);
let y_tensor = Tensor::from_vec(y_data, vec![n_samples, 1]);
let x_var = Variable::new(x_tensor, false);
let y_var = Variable::new(y_tensor, false);
let model = Linear::new(n_features, 1);
let params = model.parameters();
let mut optimizer = SGD::new(0.01);
let n_epochs = 100;
println!("Starting training...");
for epoch in 0..n_epochs {
optimizer.zero_grad();
let output = model.forward(&x_var);
let loss_var = mse_loss(&output, &y_var);
loss_var.backward();
for param in ¶ms {
let param_data = param.data();
let param_tensor = param_data.read().unwrap();
let grad_data = param.grad();
let grad_guard = grad_data.read().unwrap();
if let Some(ref grad_tensor) = *grad_guard {
optimizer.step(¶m_tensor, grad_tensor);
}
}
if epoch % 10 == 0 {
let loss_data = loss_var.data();
let loss_value = loss_data.read().unwrap();
println!(
"Epoch {}: Loss = {:.6}",
epoch,
loss_value.as_array().iter().next().unwrap_or(&0.0)
);
}
}
println!("Training completed!");
}