use super::Tensor;
use crate::{
approx::{approx_eq, ApproxEquality, RelativeEq},
nn::tensors::TensorGrad,
};
use tensor_optim::TensorOps;
#[derive(Debug, Default, Clone, Copy)]
pub struct TestEval {
pub loss: f32,
pub acc: f32,
pub score: f32,
}
impl TestEval {
pub const ZERO: Self = Self::new();
pub const INF_LOSS: Self = Self {
loss: f32::INFINITY,
acc: 0.0,
score: 0.0,
};
pub const NEG_INF_LOSS: Self = Self {
loss: f32::NEG_INFINITY,
acc: 100.0,
score: 100.0,
};
#[must_use]
pub const fn new() -> Self {
Self {
loss: 0.0,
acc: 0.0,
score: 0.0,
}
}
#[must_use]
pub const fn is_better_than(&self, rhs: &Self) -> bool {
self.loss < rhs.loss
}
#[must_use]
pub const fn best_of<'a>(&'a self, rhs: &'a Self) -> &'a Self {
if self.is_better_than(rhs) {
self
} else {
rhs
}
}
pub const fn set_if_better<'a>(&'a mut self, rhs: &'a Self) {
if rhs.is_better_than(self) {
*self = *rhs;
}
}
}
fn __percentage_correct<const D: usize, const N: usize>(
output: &Tensor<D, N>,
target: &Tensor<D, N>,
) -> f32 {
let mut correct = 0f32;
for (a, b) in output.data().iter().zip(target.data().iter()) {
let prec = (a - b).approx_eq(&0.0);
if prec == ApproxEquality::Precise {
correct += 1.0;
} else if prec == ApproxEquality::Partial {
correct += 0.5;
} else if prec == ApproxEquality::Relative {
correct += 0.25;
} else if (a - b).abs() < 0.1 {
correct += 0.05;
}
}
(correct * 100.0) / (target.len() as f32)
}
#[must_use]
#[cfg(feature = "dyntensor")]
pub fn percentage_correct(output: &Tensor<0, 0>, target: &Tensor<0, 0>) -> f32 {
__percentage_correct::<0, 0>(output, target)
}
#[must_use]
#[cfg(not(feature = "dyntensor"))]
pub fn percentage_correct<const D: usize, const N: usize>(
output: &Tensor<D, N>,
target: &Tensor<D, N>,
) -> f32 {
__percentage_correct::<D, N>(output, target)
}
fn __accuracy_of<const D: usize, const N: usize>(
output: &Tensor<D, N>,
target: &Tensor<D, N>,
) -> f32 {
let mut correct = 0f32;
for (a, b) in output.data().iter().zip(target.data().iter()) {
if approx_eq(a, b) {
correct += 1.0;
}
}
(correct * 100.0) / (target.len().min(output.len()) as f32)
}
#[must_use]
#[cfg(feature = "dyntensor")]
pub fn accuracy_of(output: &Tensor<0, 0>, target: &Tensor<0, 0>) -> f32 {
__accuracy_of::<0, 0>(output, target)
}
#[must_use]
#[cfg(not(feature = "dyntensor"))]
pub fn accuracy_of<const D: usize, const N: usize>(
output: &Tensor<D, N>,
target: &Tensor<D, N>,
) -> f32 {
__accuracy_of::<D, N>(output, target)
}