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
pub use crate::std::engine_std::EngineStdError;
pub use crate::std::layers_std::{DenseLayerDesc, LayerSpec};
pub use native_neural_network::activations::ActivationKind;

#[derive(Debug, Clone)]
pub struct NeuralNetworkStd {
    pub layers: Vec<usize>,
    pub weights: Vec<f32>,
    pub biases: Vec<f32>,
}

impl NeuralNetworkStd {
    pub fn from_parts(layers: Vec<usize>, weights: Vec<f32>, biases: Vec<f32>) -> Option<Self> {
        if layers.len() < 2 {
            return None;
        }
        let mut expected_w = 0usize;
        let mut expected_b = 0usize;
        for i in 0..layers.len() - 1 {
            let in_sz = layers[i];
            let out_sz = layers[i + 1];
            expected_w = expected_w.saturating_add(in_sz.saturating_mul(out_sz));
            expected_b = expected_b.saturating_add(out_sz);
        }
        if weights.len() != expected_w || biases.len() != expected_b {
            return None;
        }
        Some(NeuralNetworkStd {
            layers,
            weights,
            biases,
        })
    }

    pub fn expected_weights_count(layers: &[usize]) -> Option<usize> {
        native_neural_network::network::NeuralNetwork::expected_weights_count(layers)
    }

    pub fn expected_biases_count(layers: &[usize]) -> Option<usize> {
        native_neural_network::network::NeuralNetwork::expected_biases_count(layers)
    }

    pub fn layer_count(&self) -> usize {
        self.layers.len().saturating_sub(1)
    }

    pub fn build_layer_specs(
        &self,
        hidden_activation: ActivationKind,
        output_activation: ActivationKind,
    ) -> Option<Vec<LayerSpec>> {
        let layer_count = self.layer_count();
        if layer_count == 0 {
            return None;
        }
        let mut native_out = vec![
            native_neural_network::layers::LayerSpec::Dense(
                native_neural_network::layers::DenseLayerDesc {
                    input_size: 0,
                    output_size: 0,
                    weight_offset: 0,
                    bias_offset: 0,
                    activation: ActivationKind::Identity
                }
            );
            layer_count
        ];

        let mut w_off = 0usize;
        let mut b_off = 0usize;

        for (i, slot) in native_out.iter_mut().enumerate().take(layer_count) {
            let in_size = self.layers[i];
            let out_size = self.layers[i + 1];
            let weight_len = in_size.checked_mul(out_size)?;
            let activation = if i + 1 == layer_count {
                output_activation
            } else {
                hidden_activation
            };

            *slot = native_neural_network::layers::LayerSpec::Dense(
                native_neural_network::layers::DenseLayerDesc {
                    input_size: in_size,
                    output_size: out_size,
                    weight_offset: w_off,
                    bias_offset: b_off,
                    activation,
                },
            );

            w_off = w_off.checked_add(weight_len)?;
            b_off = b_off.checked_add(out_size)?;
        }

        if w_off != self.weights.len() || b_off != self.biases.len() {
            return None;
        }
        Some(
            native_out
                .into_iter()
                .map(crate::std::layers_std::LayerSpec::from)
                .collect(),
        )
    }

    pub fn forward(
        &self,
        input: &[f32],
        output: &mut [f32],
        scratch: &mut [f32],
        hidden_activation: ActivationKind,
        output_activation: ActivationKind,
    ) -> Result<(), EngineStdError> {
        let specs = self
            .build_layer_specs(hidden_activation, output_activation)
            .ok_or(EngineStdError::InvalidPlan)?;
        let plan_std = crate::std::layers_std::LayerPlanStd::new(
            specs,
            self.weights.clone(),
            self.biases.clone(),
        );
        crate::std::engine_std::forward_plan(&plan_std, input, output, scratch)
    }
}