use crate::linalg::Matrix;
use crate::loss::Loss;
use crate::Float;
pub struct MAPE<T: Float>(T);
impl<T: Float> MAPE<T> {
pub fn new(datatype_number: T) -> Self {
Self(datatype_number)
}
}
impl<T: Float> Loss<T> for MAPE<T> {
fn call(&self, output: &Matrix<T>, target: &Matrix<T>) -> T {
if output.shape() != target.shape() {
panic!("!!!Size of output matrix and target must be equal!!!\nOutput size:{:?} Target size: {:?}", output.shape(), target.shape())
}
let length = output.data.len();
let diff = output - target;
let mut total_loss = T::default();
for i in 0..length {
if target.data[i] != T::default() {
total_loss += (diff.data[i] / target.data[i]).abs();
}
}
total_loss / T::from_usize(length)
}
fn gradient(&self, output: &Matrix<T>, target: &Matrix<T>) -> Matrix<T> {
if output.shape() != target.shape() {
panic!("!!!Size of output matrix and target must be equal!!!")
}
let length = output.data.len();
let mut grad = vec![T::default(); length];
for i in 0..length {
if target.data[i] != T::default() {
let sign = if output.data[i] > target.data[i] {
T::one() } else if output.data[i] < target.data[i] {
Float::neg(T::one()) } else {
T::default() };
grad[i] = sign / target.data[i];
}
}
Matrix::new(grad, target.rows, output.cols) * (T::from_usize(1) / T::from_usize(length))
}
}