native_neural_network_std 0.2.1

Ergonomic std wrapper for the `native_neural_network` crate (no_std) — std-friendly re-exports and utilities.
Documentation
use native_neural_network_std as nn;
mod utils {
    include!("test_utils.rs");
}

#[test]
fn cpu_backend_abstraction_real() {
    let previous = native_neural_network_std::std::engine_std::get_compute_backend();
    native_neural_network_std::std::engine_std::set_compute_backend(
        native_neural_network_std::std::engine_std::ComputeBackend::Cpu,
    );
    assert_eq!(
        native_neural_network_std::std::engine_std::get_compute_backend(),
        native_neural_network_std::std::engine_std::ComputeBackend::Cpu
    );
    let layers = vec![
        native_neural_network_std::std::layers_std::LayerSpec::Dense(
            native_neural_network_std::std::layers_std::DenseLayerDesc {
                input_size: 2,
                output_size: 1,
                weight_offset: 0,
                bias_offset: 0,
                activation:
                    native_neural_network_std::std::activations_std::ActivationKind::Identity,
            },
        ),
    ];
    let plan = native_neural_network_std::std::layers_std::LayerPlanStd::new(
        layers,
        vec![2.0f32, 3.0f32],
        vec![1.0f32],
    );
    let input = vec![1.0f32, 2.0f32];
    let mut output = vec![0.0f32; 1];
    let mut scratch =
        vec![
            0.0f32;
            native_neural_network_std::std::engine_std::required_batch_scratch_len(&plan, 1)
                .unwrap_or(0)
        ];
    native_neural_network_std::std::engine_std::forward_plan_big_kernel(
        &plan,
        &input,
        &mut output,
        1,
        &mut scratch,
    )
    .expect("cpu forward");
    assert!((output[0] - 9.0).abs() < 1e-6);
    native_neural_network_std::std::engine_std::set_compute_backend(previous);
}

#[test]
fn differential_softmax_vs_stable() {
    let mut rng = utils::XorShift32::new(0x12345678);
    for _ in 0..1000 {
        let len = 1 + (rng.next_u32() % 32) as usize;
        let mut v1 = vec![0f32; len];
        for i in 0..len {
            v1[i] = rng.next_f32() * 20.0;
        }
        let mut out1 = vec![0f32; len];
        let mut out2 = vec![0f32; len];
        nn::std::inference_std::softmax(&v1, &mut out1).ok();
        nn::std::inference_std::softmax_stable(&v1, &mut out2).ok();
        for i in 0..len {
            assert!(
                utils::approx_eq(out1[i], out2[i], 1e-4),
                "softmax mismatch at {}: {} vs {}",
                i,
                out1[i],
                out2[i]
            );
        }
    }
}