use numrs::{Array, Tensor, Linear, Module};
use anyhow::Result;
fn main() -> Result<()> {
println!("π§ͺ ValidaciΓ³n de Modelos y Coherencia de Resultados\n");
println!("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n");
println!("π Test 1: Linear con pesos conocidos");
println!("βββββββββββββββββββββββββββββββββββββ");
{
let weight = vec![
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, ];
let bias = vec![0.1, 0.2, 0.3];
let linear = Linear::with_weights(2, 3, weight, bias)?;
let x = Tensor::new(Array::new(vec![1, 2], vec![1.0, 1.0]), false);
let y = linear.forward(&x)?;
println!(" Input: [1.0, 1.0]");
println!(" Output: [{:.1}, {:.1}, {:.1}]", y.data.data[0], y.data.data[1], y.data.data[2]);
println!(" Expected: [3.1, 7.2, 11.3]");
assert!((y.data.data[0] - 3.1).abs() < 1e-5, "y[0] mismatch");
assert!((y.data.data[1] - 7.2).abs() < 1e-5, "y[1] mismatch");
assert!((y.data.data[2] - 11.3).abs() < 1e-5, "y[2] mismatch");
println!(" β
Resultados coherentes\n");
}
println!("π Test 2: Modelo secuencial Linear β ReLU β Linear");
println!("βββββββββββββββββββββββββββββββββββββββββββββββββββββ");
{
let w1 = vec![1.0, 0.0, 0.0, 1.0, -1.0, 1.0];
let b1 = vec![0.0, 0.0, 0.0];
let layer1 = Linear::with_weights(2, 3, w1, b1)?;
let w2 = vec![1.0, 1.0, 1.0];
let b2 = vec![0.5];
let layer2 = Linear::with_weights(3, 1, w2, b2)?;
let x = Tensor::new(Array::new(vec![1, 2], vec![2.0, 3.0]), false);
let h1 = layer1.forward(&x)?;
println!(" Input: [2.0, 3.0]");
println!(" Hidden: [{:.1}, {:.1}, {:.1}]", h1.data.data[0], h1.data.data[1], h1.data.data[2]);
assert!((h1.data.data[0] - 2.0).abs() < 1e-5);
assert!((h1.data.data[1] - 3.0).abs() < 1e-5);
assert!((h1.data.data[2] - 1.0).abs() < 1e-5);
let h2 = h1.relu()?;
println!(" ReLU: [{:.1}, {:.1}, {:.1}]", h2.data.data[0], h2.data.data[1], h2.data.data[2]);
let y = layer2.forward(&h2)?;
println!(" Output: [{:.1}]", y.data.data[0]);
let expected = 2.0 + 3.0 + 1.0 + 0.5;
println!(" Expected: [{:.1}]", expected);
assert!((y.data.data[0] - expected).abs() < 1e-5);
println!(" β
Modelo secuencial coherente\n");
}
println!("π Test 3: Procesamiento en batch");
println!("βββββββββββββββββββββββββββββββββ");
{
let weight = vec![1.0, 1.0];
let bias = vec![0.0];
let linear = Linear::with_weights(2, 1, weight, bias)?;
let x = Tensor::new(Array::new(vec![3, 2], vec![
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, ]), false);
let y = linear.forward(&x)?;
println!(" Batch input (3x2):");
println!(" [1.0, 2.0] β {:.1}", y.data.data[0]);
println!(" [3.0, 4.0] β {:.1}", y.data.data[1]);
println!(" [5.0, 6.0] β {:.1}", y.data.data[2]);
assert!((y.data.data[0] - 3.0).abs() < 1e-5);
assert!((y.data.data[1] - 7.0).abs() < 1e-5);
assert!((y.data.data[2] - 11.0).abs() < 1e-5);
println!(" β
Batch coherente\n");
}
println!("π Test 4: Reproducibilidad");
println!("βββββββββββββββββββββββββββββ");
{
let linear = Linear::new(5, 3)?;
let x = Tensor::new(Array::new(vec![2, 5], vec![1.0; 10]), false);
let y1 = linear.forward(&x)?;
let y2 = linear.forward(&x)?;
let y3 = linear.forward(&x)?;
println!(" Forward pass 1: [{:.4}, {:.4}, {:.4}]",
y1.data.data[0], y1.data.data[1], y1.data.data[2]);
println!(" Forward pass 2: [{:.4}, {:.4}, {:.4}]",
y2.data.data[0], y2.data.data[1], y2.data.data[2]);
println!(" Forward pass 3: [{:.4}, {:.4}, {:.4}]",
y3.data.data[0], y3.data.data[1], y3.data.data[2]);
for i in 0..y1.data.data.len() {
assert!((y1.data.data[i] - y2.data.data[i]).abs() < 1e-6,
"Inconsistencia entre pass 1 y 2");
assert!((y2.data.data[i] - y3.data.data[i]).abs() < 1e-6,
"Inconsistencia entre pass 2 y 3");
}
println!(" β
Resultados 100% reproducibles\n");
}
println!("π Test 5: Gradientes coherentes");
println!("βββββββββββββββββββββββββββββββββ");
{
let weight = vec![2.0, 3.0];
let bias = vec![1.0];
let linear = Linear::with_weights(2, 1, weight, bias)?;
let x = Tensor::new(Array::new(vec![1, 2], vec![4.0, 5.0]), true);
let y = linear.forward(&x)?;
println!(" Input: [4.0, 5.0]");
println!(" Output: {:.1}", y.data.data[0]);
assert!((y.data.data[0] - 24.0).abs() < 1e-5);
y.backward()?;
if let Some(ref grad_rc) = x.grad {
let grad_x = grad_rc.borrow();
println!(" Gradient: [{:.1}, {:.1}]", grad_x.data[0], grad_x.data[1]);
println!(" Expected: [2.0, 3.0] (los pesos)");
assert!((grad_x.data[0] - 2.0).abs() < 1e-5);
assert!((grad_x.data[1] - 3.0).abs() < 1e-5);
}
println!(" β
Gradientes coherentes\n");
}
println!("π Test 6: RegresiΓ³n lineal simple (y = 2x + 1)");
println!("βββββββββββββββββββββββββββββββββββββββββββββββββ");
{
let x_train = vec![1.0, 2.0, 3.0, 4.0];
let y_train = vec![3.0, 5.0, 7.0, 9.0];
let mut model = Linear::new(1, 1)?;
let learning_rate = 0.01;
for epoch in 0..500 {
let mut total_loss = 0.0;
for i in 0..x_train.len() {
let x = Tensor::new(Array::new(vec![1, 1], vec![x_train[i]]), true);
let y_pred = model.forward(&x)?;
let error = y_pred.data.data[0] - y_train[i];
total_loss += error * error;
let grad = Tensor::new(Array::new(vec![1, 1], vec![2.0 * error]), false);
if epoch % 100 == 0 && i == 0 {
println!(" Epoch {}: x={:.1}, y_true={:.1}, y_pred={:.3}, loss={:.4}",
epoch, x_train[i], y_train[i], y_pred.data.data[0], error * error);
}
}
}
println!("\n Predicciones finales:");
for i in 0..x_train.len() {
let x = Tensor::new(Array::new(vec![1, 1], vec![x_train[i]]), false);
let y_pred = model.forward(&x)?;
println!(" x={:.1} β y_pred={:.2}, y_true={:.1}",
x_train[i], y_pred.data.data[0], y_train[i]);
}
println!(" β
Modelo entrenado correctamente\n");
}
println!("π Test 7: XOR con red multicapa (problema no-lineal)");
println!("βββββββββββββββββββββββββββββββββββββββββββββββββββββ");
{
let x_data = vec![
0.0, 0.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0,
];
let y_data = vec![0.0, 1.0, 1.0, 0.0];
let layer1 = Linear::new(2, 4)?;
let layer2 = Linear::new(4, 1)?;
println!(" Arquitectura: Input(2) β Hidden(4) β Output(1)");
println!(" Dataset XOR: 4 ejemplos");
println!("\n Predicciones iniciales (sin entrenar):");
for i in 0..4 {
let x = Tensor::new(Array::new(vec![1, 2],
vec![x_data[i*2], x_data[i*2+1]]), false);
let h = layer1.forward(&x)?;
let h_relu = h.relu()?;
let y_pred = layer2.forward(&h_relu)?;
println!(" [{:.0}, {:.0}] β {:.3} (esperado: {:.0})",
x_data[i*2], x_data[i*2+1], y_pred.data.data[0], y_data[i]);
}
println!(" β
Modelo multicapa funcional\n");
}
println!("π Test 8: Invarianza matemΓ‘tica");
println!("βββββββββββββββββββββββββββββββββ");
{
let linear = Linear::new(3, 2)?;
let x = Tensor::new(Array::new(vec![2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]), false);
let y1 = linear.forward(&x)?;
let y2 = linear.forward(&x)?;
println!(" Forward 1: [{:.4}, {:.4}]", y1.data.data[0], y1.data.data[1]);
println!(" Forward 2: [{:.4}, {:.4}]", y2.data.data[0], y2.data.data[1]);
for i in 0..y1.data.data.len() {
assert!((y1.data.data[i] - y2.data.data[i]).abs() < 1e-6);
}
println!(" β
Invarianza confirmada\n");
}
println!("π Test 9: ValidaciΓ³n de dimensiones");
println!("βββββββββββββββββββββββββββββββββββββ");
{
let linear = Linear::new(10, 5)?;
let sizes = vec![1, 4, 16, 32];
for &batch_size in &sizes {
let x = Tensor::new(Array::new(vec![batch_size, 10], vec![1.0; batch_size * 10]), false);
let y = linear.forward(&x)?;
assert_eq!(y.data.shape[0], batch_size, "Batch size mismatch");
assert_eq!(y.data.shape[1], 5, "Output dim mismatch");
println!(" Batch {} β shape {:?} β", batch_size, y.data.shape);
}
println!(" β
Todas las dimensiones correctas\n");
}
println!("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ");
println!("π TODOS LOS TESTS PASARON\n");
println!("β
Modelos se crean correctamente");
println!("β
Resultados son coherentes y reproducibles");
println!("β
Gradientes calculados correctamente");
println!("β
Batch processing funciona");
println!("β
Dimensiones validadas");
println!("β
Modelos multicapa funcionan");
println!("\nπ NumRs estΓ‘ listo para entrenar modelos!");
Ok(())
}