use crate::compat::*;
use crate::module::Module;
use hodu_core::{error::HoduResult, tensor::Tensor};
#[derive(Module, Clone)]
#[module(inputs = 2)]
pub struct CrossEntropyLoss {
dim: i32,
}
impl CrossEntropyLoss {
pub fn new() -> Self {
Self { dim: -1 }
}
pub fn with_dim(dim: i32) -> Self {
Self { dim }
}
pub fn forward(&self, (logits, target): (&Tensor, &Tensor)) -> HoduResult<Tensor> {
let log_probs = logits.log_softmax(self.dim)?;
let rank = log_probs.get_layout().get_shape().len() as i32;
let gather_dim = if self.dim < 0 {
rank + self.dim
} else {
self.dim
};
let target_unsqueezed = target.unsqueeze(-1)?;
let gathered = log_probs.gather(gather_dim as i64, &target_unsqueezed)?;
let gathered_squeezed = gathered.squeeze(Some(-1))?;
let nll = gathered_squeezed.neg()?;
nll.mean_all()
}
}