use native_neural_network_std::std::activations_std::ActivationKind;
use native_neural_network_std::std::engine_std::forward_plan;
use native_neural_network_std::std::layers_std::{DenseLayerDesc, LayerPlanStd, LayerSpec};
use native_neural_network_std::std::model_format_std::{decode_model, encode_model, encoded_size};
use native_neural_network_std::std::model_std::ModelStd;
use native_neural_network_std::std::visualization_std::get_network_from_rnn;
fn lcg_u32(mut s: u32) -> impl Iterator<Item = u8> {
std::iter::from_fn(move || {
s = s.wrapping_mul(1664525).wrapping_add(1013904223);
Some((s & 0xff) as u8)
})
}
#[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 fuzz_decode_model_no_panic() {
let mut gen = lcg_u32(0x1234_5678);
for len in 0..200 {
let mut buf = Vec::with_capacity(len);
for _ in 0..len {
buf.push(gen.next().unwrap());
}
let mut layers_out = vec![
LayerSpec::Dense(DenseLayerDesc {
input_size: 0,
output_size: 0,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity
});
1
];
let mut weights_out = vec![0f32; 4];
let mut biases_out = vec![0f32; 2];
let res = decode_model(&buf, &mut layers_out, &mut weights_out, &mut biases_out);
assert!(res.is_ok() || res.is_err());
}
}
#[test]
fn decode_empty_zero_sizes_roundtrip() {
let size = encoded_size(0usize, 0usize, 0usize).expect("size for zero counts");
let mut buf = vec![0u8; size];
let used = encode_model(&[], &[], &[], &mut buf).expect("encode empty");
assert!(used <= buf.len());
let mut out_layers = vec![
LayerSpec::Dense(DenseLayerDesc {
input_size: 0,
output_size: 0,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity
});
1
];
let mut weights_out = vec![0f32; 0];
let mut biases_out = vec![0f32; 0];
let res = decode_model(
&buf[..used],
&mut out_layers,
&mut weights_out,
&mut biases_out,
);
assert!(res.is_err());
}
#[test]
fn nan_and_inf_propagate_safely() {
let layers = vec![LayerSpec::Dense(DenseLayerDesc {
input_size: 2,
output_size: 1,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity,
})];
let weights = vec![f32::NAN, f32::INFINITY];
let biases = vec![0.0f32];
let size = encoded_size(layers.len(), weights.len(), biases.len()).unwrap();
let mut buf = vec![0u8; size];
let used = encode_model(&layers, &weights, &biases, &mut buf).expect("encode");
buf.truncate(used);
let m = ModelStd::from_bytes(&buf).expect("from_bytes");
let out = m.run_single(&[1.0f32, 1.0f32]).expect("run");
assert!(!out[0].is_finite());
}
#[test]
fn forward_plan_matches_model_run() {
let layers = vec![LayerSpec::Dense(DenseLayerDesc {
input_size: 2,
output_size: 1,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity,
})];
let weights = vec![1.5f32, -0.5f32];
let biases = vec![0.25f32];
let size = encoded_size(layers.len(), weights.len(), biases.len()).unwrap();
let mut buf = vec![0u8; size];
let used = encode_model(&layers, &weights, &biases, &mut buf).unwrap();
buf.truncate(used);
let m = ModelStd::from_bytes(&buf).unwrap();
let single = m.run_single(&[2.0f32, 3.0f32]).unwrap();
let plan = LayerPlanStd::new(m.layers.clone(), m.weights.clone(), m.biases.clone());
let mut out = vec![0f32; m.output_size];
let mut scratch = vec![0f32; m.infer_scratch_len.max(16)];
forward_plan(&plan, &[2.0f32, 3.0f32], &mut out, &mut scratch).unwrap();
assert_eq!(single, out);
}
#[test]
fn ffi_create_null_pointer_returns_null() {
let h = native_neural_network_std::std::ffi_api_std::rnn_ffi_model_create_from_bytes(&[]);
assert_eq!(h, 0usize);
}
#[test]
fn ffi_destroy_null_is_noop() {
native_neural_network_std::std::ffi_api_std::rnn_ffi_model_destroy(0usize);
assert!(true);
}
#[test]
fn parse_rnn_fuzz_no_panic() {
let mut gen = lcg_u32(0xfeed_f00d);
for len in 0..150 {
let mut buf = Vec::with_capacity(len);
for _ in 0..len {
buf.push(gen.next().unwrap());
}
let res = get_network_from_rnn(&buf);
assert!(res.is_ok() || res.is_err());
}
}
#[test]
fn batch_large_sanity() {
let layers = vec![LayerSpec::Dense(DenseLayerDesc {
input_size: 2,
output_size: 1,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity,
})];
let weights = vec![1.0f32, 1.0f32];
let biases = vec![0.0f32];
let size = encoded_size(layers.len(), weights.len(), biases.len()).unwrap();
let mut buf = vec![0u8; size];
let used = encode_model(&layers, &weights, &biases, &mut buf).unwrap();
buf.truncate(used);
let mut input = Vec::with_capacity(2000);
for i in 0..1000 {
input.push(i as f32);
input.push((i + 1) as f32);
}
let m = ModelStd::from_bytes(&buf).expect("from_bytes");
let out = m.run_batch(&input, 1000).expect("batch");
assert_eq!(out.len(), 1000 * m.output_size);
}
#[test]
fn concurrent_init_no_panic() {
native_neural_network_std::shutdown();
let mut th = Vec::new();
for _ in 0..32 {
th.push(std::thread::spawn(|| {
let res = native_neural_network_std::init();
match res {
Ok(()) => {}
Err(_) => {}
}
}));
}
for t in th {
let r = t.join();
assert!(r.is_ok());
}
assert!(native_neural_network_std::is_initialized());
native_neural_network_std::shutdown();
}