use crate::error::Error;
use crate::neural_network::Tensor;
use ndarray::{Array2, ArrayView2};
const PROB_CLIP_EPS: f32 = 1e-7;
fn stable_log_softmax_softmax(logits: &ArrayView2<f32>) -> (Array2<f32>, Array2<f32>) {
let mut log_sm = logits.to_owned();
for mut row in log_sm.rows_mut() {
let max = row.iter().cloned().fold(f32::NEG_INFINITY, f32::max);
let sum_exp: f32 = row.iter().map(|&x| (x - max).exp()).sum();
let log_sum_exp = max + sum_exp.ln();
row.mapv_inplace(|x| x - log_sum_exp);
}
let sm = log_sm.mapv(|v| v.exp());
(log_sm, sm)
}
fn validate_same_shape(y_true: &Tensor, y_pred: &Tensor) -> Result<(), Error> {
if y_true.shape() != y_pred.shape() {
return Err(Error::shape_mismatch(y_true.shape(), y_pred.shape()));
}
Ok(())
}
fn clip_probabilities(probs: &Tensor) -> Tensor {
let mut clipped = probs.clone();
clipped.par_mapv_inplace(|x| x.clamp(PROB_CLIP_EPS, 1.0 - PROB_CLIP_EPS));
clipped
}
pub mod binary_cross_entropy;
pub mod categorical_cross_entropy;
pub mod mean_absolute_error;
pub mod mean_squared_error;
pub mod sparse_categorical_cross_entropy;
pub use binary_cross_entropy::BinaryCrossEntropy;
pub use categorical_cross_entropy::CategoricalCrossEntropy;
pub use mean_absolute_error::MeanAbsoluteError;
pub use mean_squared_error::MeanSquaredError;
pub use sparse_categorical_cross_entropy::SparseCategoricalCrossEntropy;