use native_neural_network_std::std::activations_std::ActivationKind;
use native_neural_network_std::std::engine_std::{
get_compute_backend, set_compute_backend, ComputeBackend,
};
use native_neural_network_std::std::layers_std::{DenseLayerDesc, LayerSpec};
#[test]
fn cpu_backend_abstraction_real() {
let previous = get_compute_backend();
set_compute_backend(ComputeBackend::Cpu);
assert_eq!(get_compute_backend(), ComputeBackend::Cpu);
set_compute_backend(previous);
}
#[test]
fn rnn_api_basic_topology_and_pack_run() {
use native_neural_network_std::std::rnn_std as rstd;
let topology = &[2usize, 1usize];
let decoded = rstd::rnn_required_from_topology(topology).expect("required counts");
assert_eq!(decoded.layers, 1);
let weights = vec![1.0f32, 1.0f32];
let biases = vec![0.5f32];
let mut layer_scratch = vec![
LayerSpec::Dense(DenseLayerDesc {
input_size: 0,
output_size: 0,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity
});
1
];
let mut out_bytes = vec![0u8; 8192];
let written = rstd::rnn_pack_v1(
topology,
ActivationKind::Identity,
ActivationKind::Identity,
&weights,
&biases,
&mut layer_scratch,
&mut out_bytes,
)
.expect("pack");
assert!(written > 0);
let input = [2.0f32, 3.0f32];
let mut output = [0f32; 1];
let infer_scratch_len =
rstd::rnn_required_infer_scratch_from_specs_std(&layer_scratch).unwrap_or(0);
let mut weights_scratch = vec![0f32; decoded.weights];
let mut biases_scratch = vec![0f32; decoded.biases];
let mut infer_scratch = vec![0f32; infer_scratch_len];
let res = rstd::rnn_run_v1(
&out_bytes[..written],
&input,
&mut output,
&mut layer_scratch,
&mut weights_scratch,
&mut biases_scratch,
&mut infer_scratch,
);
assert!(res.is_ok());
assert!((output[0] - (2.0 + 3.0 + 0.5)).abs() < 1e-5);
}
#[test]
fn rnn_validate_topology_and_buffers() {
use native_neural_network_std::std::rnn_std as rstd;
let good = vec![2usize, 1usize];
assert!(rstd::rnn_validate_topology(&good).is_ok());
let bad = vec![1usize];
assert!(rstd::rnn_validate_topology(&bad).is_err());
let cap = rstd::rnn_required_buffers(&good).expect("capacity");
assert_eq!(cap.layer_specs, 1);
assert_eq!(cap.weights, 2);
assert_eq!(cap.biases, 1);
}
#[test]
fn rnn_pack_and_required_counts_roundtrip() {
use native_neural_network_std::std::rnn_std as rstd;
let topology = &[2usize, 1usize];
let weights = vec![1.0f32, 1.0f32];
let biases = vec![0.5f32];
let mut layer_scratch = vec![
LayerSpec::Dense(DenseLayerDesc {
input_size: 0,
output_size: 0,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity
});
1
];
let mut out_bytes = vec![0u8; 8192];
let written = rstd::rnn_pack_v1(
topology,
ActivationKind::Identity,
ActivationKind::Identity,
&weights,
&biases,
&mut layer_scratch,
&mut out_bytes,
)
.expect("pack");
let counts = rstd::rnn_required_from_bytes_v1_std(&out_bytes[..written]).expect("counts");
assert_eq!(counts.layers, 1);
assert_eq!(counts.weights, 2);
assert_eq!(counts.biases, 1);
}
#[test]
fn rnn_run_errors_on_small_buffers() {
use native_neural_network_std::std::rnn_std as rstd;
let topology = &[2usize, 1usize];
let weights = vec![1.0f32, 1.0f32];
let biases = vec![0.5f32];
let mut layer_scratch = vec![
LayerSpec::Dense(DenseLayerDesc {
input_size: 0,
output_size: 0,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity
});
1
];
let mut out_bytes = vec![0u8; 8192];
let written = rstd::rnn_pack_v1(
topology,
ActivationKind::Identity,
ActivationKind::Identity,
&weights,
&biases,
&mut layer_scratch,
&mut out_bytes,
)
.expect("pack");
let input = [1.0f32, 1.0f32];
let mut output = [0f32; 1];
let mut weights_scratch = vec![0f32; 0];
let mut biases_scratch = vec![0f32; 0];
let mut infer_scratch = vec![0f32; 0];
let res = rstd::rnn_run_v1(
&out_bytes[..written],
&input,
&mut output,
&mut layer_scratch,
&mut weights_scratch,
&mut biases_scratch,
&mut infer_scratch,
);
assert!(res.is_err());
}
#[test]
fn rnn_pack_invalid_topology_errors() {
use native_neural_network_std::std::rnn_std as rstd;
let bad_topology = &[1usize];
let weights = vec![];
let biases = vec![];
let mut layer_scratch: Vec<LayerSpec> = Vec::new();
let mut out_bytes = vec![0u8; 16];
let res = rstd::rnn_pack_v1(
bad_topology,
ActivationKind::Identity,
ActivationKind::Identity,
&weights,
&biases,
&mut layer_scratch,
&mut out_bytes,
);
assert!(res.is_err());
}
#[test]
fn rnn_required_from_topology_bad() {
use native_neural_network_std::std::rnn_std as rstd;
let bad = &[0usize];
assert!(rstd::rnn_required_from_topology(bad).is_err());
}
#[test]
fn rnn_unpack_truncated_bytes_errors() {
use native_neural_network_std::std::rnn_std as rstd;
let bytes = [0u8, 1u8, 2u8];
let res = rstd::rnn_unpack_v1_std(&bytes);
assert!(res.is_err());
}
#[test]
fn rnn_required_from_bytes_bad_magic() {
use native_neural_network_std::std::rnn_std as rstd;
let bad = [0u8; 4];
assert!(rstd::rnn_required_from_bytes_v1_std(&bad).is_err());
}
#[test]
fn rnn_concurrent_pack_and_run_smoketest() {
use native_neural_network_std::std::rnn_std as rstd;
use std::thread;
let mut handles = Vec::new();
for _ in 0..4 {
handles.push(thread::spawn(|| {
let topology = &[2usize, 1usize];
let weights = vec![1.0f32, 1.0f32];
let biases = vec![0.5f32];
let mut layer_scratch = vec![
LayerSpec::Dense(DenseLayerDesc {
input_size: 0,
output_size: 0,
weight_offset: 0,
bias_offset: 0,
activation: ActivationKind::Identity
});
1
];
let mut out_bytes = vec![0u8; 8192];
let written = rstd::rnn_pack_v1(
topology,
ActivationKind::Identity,
ActivationKind::Identity,
&weights,
&biases,
&mut layer_scratch,
&mut out_bytes,
)
.expect("pack");
let input = [1.0f32, 2.0f32];
let mut out = [0f32; 1];
let mut weights_scratch = vec![0f32; 2];
let mut biases_scratch = vec![0f32; 1];
let mut infer_scratch =
vec![
0f32;
rstd::rnn_required_infer_scratch_from_specs_std(&layer_scratch).unwrap_or(0)
];
let r = rstd::rnn_run_v1(
&out_bytes[..written],
&input,
&mut out,
&mut layer_scratch,
&mut weights_scratch,
&mut biases_scratch,
&mut infer_scratch,
);
assert!(r.is_ok());
}));
}
for h in handles {
h.join().unwrap();
}
}