Files
foxhunt/crates
jgrusewski 999bb2fa0c diag(policy-quality): NoisyNets σ per branch — partial Task 0.6, completes 0.10
Wires Track 1 noisy_mag/noisy_dir + Track 4 sigma_mean fields with the
mean |sigma| across each action branch's NoisyLinear fc + out layers.
Branch 0 = direction, Branch 1 = magnitude. H7 detection signal — if
magnitude branch has 2x larger σ than direction, NoisyNets noise is
dominating the magnitude head's effective signal.

Cross-crate API chain (no shortcuts):
  * ml-dqn::noisy_layers::NoisyLinear::sigma_mean() -> mean |weight_σ| + |bias_σ|
  * ml-dqn::branching::BranchingDuelingQNetwork::branch_noisy_sigma_mean(idx)
    averages fc + out σ for the named branch
  * ml-dqn::dqn::DQN::branch_noisy_sigma_mean(idx) — None-tolerant proxy
  * ml::trainers::dqn::config::DQNAgentType::branch_noisy_sigma_mean(idx)
    delegates through primary_head
  * HEALTH_DIAG reads via self.agent.read().await at epoch boundary

Pinned-readback pattern not used here — NoisyLinear weights live in
candle-managed CudaSlices, not flat trainer params buffer. Per-call
dtoh of ~256 + 768 floats × 2 layers × 4 branches = ~8KB total per
epoch. Negligible.

Track 0.10 (exploration entropy + sigma_mean) is now COMPLETE — the
sigma_mean field that was previously stubbed is now real.
Task 0.6 remains partial: VSN mask (vsn_mag, vsn_dir) and target drift
(drift_mag, drift_dir) still stubbed — they require separate accessors
on different layer types (VSN module + target_params_buf reductions).
2026-04-21 21:59:53 +02:00
..