use native_neural_network_std as nn;
mod utils {
include!("test_utils.rs");
}
fn scale_from_env() -> usize {
std::env::var("STRESS_SCALE")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(1)
}
#[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
);
native_neural_network_std::std::engine_std::set_compute_backend(previous);
}
#[test]
fn stress_training_simulation() {
let scale = scale_from_env();
let base = 16usize.saturating_mul(scale);
let layers = vec![base, base * 2, base];
let wcount =
nn::std::network_std::NeuralNetworkStd::expected_weights_count(&layers).unwrap_or(0);
let bcount =
nn::std::network_std::NeuralNetworkStd::expected_biases_count(&layers).unwrap_or(0);
let mut weights = vec![0.01f32; wcount];
let mut biases = vec![0f32; bcount];
let mut net = nn::std::network_std::NeuralNetworkStd::from_parts(
layers.clone(),
weights.clone(),
biases.clone(),
)
.expect("initial construct");
assert!(nn::std::network_std::validate_network_parts(
&net.layers,
&net.weights,
&net.biases
));
let mut backup_weights = weights.clone();
let mut backup_biases = biases.clone();
let mut rng = utils::XorShift32::new(0x1234_abcd);
let cycles = 10_000usize;
for cycle in 0..cycles {
if !weights.is_empty() {
let idx = (rng.next_u32() as usize) % weights.len();
let delta = 0.0001 * (((cycle % 7) as f32) - 3.0);
weights[idx] = utils::saturating_add_f32(weights[idx], delta);
}
if !biases.is_empty() && cycle % 50 == 0 {
let idx = (rng.next_u32() as usize) % biases.len();
biases[idx] = utils::saturating_add_f32(biases[idx], 0.00005);
}
if cycle % 2000 == 0 && cycle != 0 {
let start = ((cycle / 2000) % (biases.len().max(1))).saturating_mul(1);
let end = std::cmp::min(biases.len(), start + 4);
for b in &mut biases[start..end] {
*b = 0.0;
}
}
if cycle % 100 == 0 {
if let Ok(new_net) = nn::std::network_std::NeuralNetworkStd::from_parts(
layers.clone(),
weights.clone(),
biases.clone(),
) {
net = new_net;
nn::std::network_std::network_stats(&net.layers, &net.weights, &net.biases);
}
}
if cycle % 1000 == 0 && cycle != 0 {
backup_weights.copy_from_slice(&weights);
backup_biases.copy_from_slice(&biases);
for i in 0..(weights.len().min(10)) {
weights[i] = f32::INFINITY;
}
let ok = nn::std::network_std::validate_network_parts(&layers, &weights, &biases);
if !ok {
weights.copy_from_slice(&backup_weights);
biases.copy_from_slice(&backup_biases);
}
}
if cycle % 500 == 0 {
let _stats = nn::std::network_std::network_stats(&layers, &weights, &biases);
let _valid = nn::std::network_std::validate_network_parts(&layers, &weights, &biases);
if !weights.is_empty() {
let i = (rng.next_u32() as usize) % weights.len();
weights[i] =
utils::saturating_add_f32(weights[i], (rng.next_f32() * 2.0 - 1.0) * 1e-6);
}
}
}
assert!(
nn::std::network_std::validate_network_parts(&layers, &weights, &biases),
"final parts invalid"
);
nn::std::network_std::network_stats(&layers, &weights, &biases);
}