use optirs_learned::lstm::{LSTMNetwork, OutputProjection, OutputTransform};
use optirs_learned::transformer_based_optimizer::MultiHeadAttention;
use optirs_learned::LearnedOptimizerConfig;
use scirs2_core::ndarray::Array2;
fn variance(values: &Array2<f64>) -> f64 {
let n = values.len() as f64;
assert!(n > 1.0, "need at least two samples");
let mean = values.iter().sum::<f64>() / n;
values.iter().map(|v| (v - mean) * (v - mean)).sum::<f64>() / n
}
fn glorot_target(fan_in: usize, fan_out: usize) -> f64 {
2.0 / (fan_in + fan_out) as f64
}
#[test]
fn transformer_attention_projections_hit_the_glorot_target_variance() {
const MODEL_DIM: usize = 128;
const HEADS: usize = 8;
const HEAD_DIM: usize = MODEL_DIM / HEADS;
let limit = MultiHeadAttention::<f64>::xavier_limit(MODEL_DIM, MODEL_DIM);
let expected_limit = (6.0 / (2.0 * MODEL_DIM as f64)).sqrt();
assert!(
(limit - expected_limit).abs() < 1e-12,
"xavier_limit returned {limit}, expected {expected_limit}"
);
let implied = limit * limit / 3.0;
let target = glorot_target(MODEL_DIM, MODEL_DIM);
assert!(
(implied / target - 1.0).abs() < 1e-12,
"a uniform draw with limit {limit} has variance {implied}, target is {target}"
);
let mut attention =
MultiHeadAttention::<f64>::new(HEADS, MODEL_DIM, HEAD_DIM).expect("attention construction");
assert_eq!(
attention.parameter_count(),
4 * MODEL_DIM * MODEL_DIM,
"four square projections expected"
);
let check = |attention: &MultiHeadAttention<f64>, stage: &str| {
let (query, key, value, output) = attention.projection_snapshots();
for (name, matrix) in [
("query", query),
("key", key),
("value", value),
("output", output),
] {
assert_eq!(matrix.dim(), (MODEL_DIM, MODEL_DIM));
let observed = variance(matrix);
let ratio = observed / target;
assert!(
(0.9..1.1).contains(&ratio),
"{stage} {name} projection variance {observed:.3e} is {ratio:.3}× the Glorot \
target {target:.3e}; the old sqrt(2/(model_dim+head_dim)) limit gives 0.59×"
);
}
};
check(&attention, "constructed");
attention.reset().expect("reset");
check(&attention, "reset");
}
#[test]
fn lstm_output_projection_hits_the_glorot_target_variance() {
const IN: usize = 64;
const OUT: usize = 192;
let mut projection =
OutputProjection::<f64>::new(IN, OUT, OutputTransform::Identity).expect("projection");
let weights = projection.weight_snapshot();
assert_eq!(weights.dim(), (OUT, IN));
let target = glorot_target(IN, OUT);
let observed = variance(weights);
let ratio = observed / target;
assert!(
(0.9..1.1).contains(&ratio),
"output projection variance {observed:.3e} is {ratio:.3}× the Glorot target \
{target:.3e}; the sqrt(2/(fan_in+fan_out))-as-uniform-limit bug gives 0.33×"
);
assert!(projection.bias_snapshot().iter().all(|b| *b == 0.0));
projection.reset(IN, 32);
let resampled = projection.weight_snapshot();
assert_eq!(resampled.dim(), (32, IN));
let reset_ratio = variance(resampled) / glorot_target(IN, 32);
assert!(
(0.9..1.1).contains(&reset_ratio),
"reset projection variance is {reset_ratio:.3}× the Glorot target for its new shape"
);
}
#[test]
fn lstm_cell_gate_matrices_use_per_matrix_fan_pairs() {
const INPUT: usize = 40;
const HIDDEN: usize = 96;
let config = LearnedOptimizerConfig {
input_features: INPUT,
hidden_size: HIDDEN,
num_layers: 1,
..Default::default()
};
let network = LSTMNetwork::<f64>::new(&config).expect("network");
assert!(network.layer_count() >= 1);
let layer = network.layer(0).expect("first layer");
let weight_ih = layer.weight_ih_snapshot();
let weight_hh = layer.weight_hh_snapshot();
assert_eq!(weight_ih.dim(), (4 * HIDDEN, INPUT));
assert_eq!(weight_hh.dim(), (4 * HIDDEN, HIDDEN));
let ih_var = variance(weight_ih);
let hh_var = variance(weight_hh);
let ih_ratio = ih_var / glorot_target(INPUT, HIDDEN);
let hh_ratio = hh_var / glorot_target(HIDDEN, HIDDEN);
assert!(
(0.9..1.1).contains(&ih_ratio),
"weight_ih variance {ih_var:.3e} is {ih_ratio:.3}× its Glorot target"
);
assert!(
(0.9..1.1).contains(&hh_ratio),
"weight_hh variance {hh_var:.3e} is {hh_ratio:.3}× its Glorot target"
);
assert!(
(ih_var / hh_var - 1.0).abs() > 0.1,
"weight_ih ({ih_var:.3e}) and weight_hh ({hh_var:.3e}) have nearly equal variance, so \
they are sharing one limit instead of using their own fan pairs"
);
assert!(
ih_var > hh_var,
"weight_ih has fan sum {} vs weight_hh's {}, so its variance must be larger",
INPUT + HIDDEN,
2 * HIDDEN
);
}
#[test]
fn lstm_attention_projections_hit_the_glorot_target_variance() {
const HIDDEN: usize = 128;
let config = LearnedOptimizerConfig {
input_features: 32,
hidden_size: HIDDEN,
num_layers: 1,
use_attention: true,
attention_heads: 8,
..Default::default()
};
let network = LSTMNetwork::<f64>::new(&config).expect("network");
let attention = network
.attention_snapshot()
.expect("use_attention = true must build an attention mechanism");
let (query, key, value, output) = attention.projection_snapshots();
let target = glorot_target(HIDDEN, HIDDEN);
for (name, matrix) in [
("query", query),
("key", key),
("value", value),
("output", output),
] {
assert_eq!(matrix.dim(), (HIDDEN, HIDDEN));
let ratio = variance(matrix) / target;
assert!(
(0.9..1.1).contains(&ratio),
"{name} projection variance is {ratio:.3}× the Glorot target {target:.3e}"
);
}
}