pub fn softmax(inp: &NdArray<f32>) -> DuResult<NdArray<f32>> {
    // softmax of a scalar value is always 1.
    if matches!(inp.shape(), Shape::Scalar(_)) {
        return Ok(NdArray::new_with_values(0, [1.0][..].into())?);
    }
    // else treat the input as a collection of vectors
    let mut it = inp.as_slice().iter().cloned();
    let first = it.next().expect("no value");
    let max: f32 = it.fold(first, |max, value| value.max(max));

    let expvalues = inp
        .sub(&NdArray::from(max))
        .expect("Failed to sub max from the input")
        .map(|v: &f32| {
            let res = E.powf(*v);
            if res.is_nan() || res == 0.0 {
                // very large V's will produce an output of 0 which will be bad down the line
                1e-12
            } else {
                res
            }
        });

    let mut norm_base: NdArray<f32> = expvalues
        .iter_rows()
        .map(|row| row.iter().cloned().sum())
        .collect();

    norm_base.reshape([norm_base.shape().span() as u32, 1]);

    let mut res = expvalues;
    for (norm, row) in norm_base.iter_rows().zip(res.iter_rows_mut()) {
        debug_assert_eq!(norm.len(), 1);
        row.iter_mut().for_each(|v| *v /= norm[0]);
    }
    Ok(res)
}
/// Inp is interpreted as a either a collection of vectors, applying softmax to each row or as a
/// single vector.
///
/// Scalars will always return 1
Inp is interpreted as a either a collection of vectors, applying softmax to each row or as a
single vector.

Scalars will always return 1
Inp is interpreted as a either a collection of vectors applying softmax to each row or as a single vector . Scalars will always return 1
pub fn softmax(inp: &NdArray<f32>) -> DuResult<NdArray<f32>> {
    // softmax of a scalar value is always 1.
    if matches!(inp.shape(), Shape::Scalar(_)) {
        return Ok(NdArray::new_with_values(0, [1.0][..].into())?);
    }
    // else treat the input as a collection of vectors
    let mut it = inp.as_slice().iter().cloned();
    let first = it.next().expect("no value");
    let max: f32 = it.fold(first, |max, value| value.max(max));
    let expvalues = inp
        .sub(&NdArray::from(max))
        .expect("Failed to sub max from the input")
        .map(|v: &f32| {
            let res = E.powf(*v);
            if res.is_nan() || res == 0.0 {
                // very large V's will produce an output of 0 which will be bad down the line
                1e-12
            } else {
                res
            }
        });
    let mut norm_base: NdArray<f32> = expvalues
        .iter_rows()
        .map(|row| row.iter().cloned().sum())
        .collect();
    norm_base.reshape([norm_base.shape().span() as u32, 1]);
    let mut res = expvalues;
    for (norm, row) in norm_base.iter_rows().zip(res.iter_rows_mut()) {
        debug_assert_eq!(norm.len(), 1);
        row.iter_mut().for_each(|v| *v /= norm[0]);
    }
    Ok(res)
}
pub fn softmax ( inp : & NdArray < f32 > ) -> DuResult < NdArray < f32 > > { // softmax of a scalar value is always 1. if matches ! ( inp shape ( ) Shape Scalar ( ) ) { return Ok ( NdArray :: new_with_values ( 0 , [ 1.0 ] [ .. ] . into ( ) ) ? ) ; } // else treat the input as a collection of vectors let mut it = inp . as_slice ( ) . iter ( ) . cloned ( ) ; let first = it . next ( ) . expect ( " " ) ; let max : f32 = it . fold ( first , | max , value | value . max ( max ) ) ; let expvalues = inp . sub ( & NdArray :: from ( max ) ) . expect ( " " ) . map ( | v : & f32 | { let res = E . powf ( * v ) ; if res . is_nan ( ) || res == 0.0 { // very large V's will produce an output of 0 which will be bad down the line 1e-12 } else { res } } ) ; let mut norm_base : NdArray < f32 > = expvalues . iter_rows ( ) . map ( | row | row . iter ( ) . cloned ( ) . sum ( ) ) . collect ( ) ; norm_base . reshape ( [ norm_base . shape ( ) . span ( ) as u32 , 1 ] ) ; let mut res = expvalues ; for ( norm , row ) in norm_base . iter_rows ( ) . zip ( res . iter_rows_mut ( ) ) { debug_assert_eq ! ( norm len ( ) 1 ) ; row . iter_mut ( ) . for_each ( | v | * v /= norm [ 0 ] ) ; } Ok ( res ) }
Inp is interpreted as a either a collection of vectors, applying softmax to each row or as a
single vector.
Inp is interpreted as a either a collection of vectors applying softmax to each row or as a single vector .
inp
&NdArray<f32>