Files
foxhunt/docs
jgrusewski 0a6a615d83 fix(dqn): unify eval action selection with training Boltzmann softmax
The eval policy used strict-argmax with an ISV-tied tie-break across all four
factored heads (direction, magnitude, order, urgency). The tie threshold was
`0.01 × isv_signals[V_HALF_*_INDEX]` — i.e. 1% of the C51 atom support range
(~40 for direction). That threshold did not match the actual per-sample
Q-spread (~1.5 once the IQN trunk gradient unstuck), so tie-break never fired
and eval became pure strict-argmax over a peaked Q distribution → val argmax
glued to one direction → 1-25 trades per 214k-bar window across cluster runs
`vg2r9` and `vnwtn`.

Replace with the same Boltzmann softmax training already uses: `tau =
max(q_range, floor)` where `q_range` is computed per-sample. Softmax is
mathematically bounded to `P(best) ≤ 47.5%` for 4 actions with `tau=q_range`,
so eval can never collapse to pure-greedy regardless of how peaked the
Q-values become. State-adaptive without tuned constants — confident states
(large q_range) still favour the best direction near-deterministically;
ambiguous states (q_range at floor) sample uniformly. The Philox stream is
seeded by (i, timestep) so eval remains bit-reproducible across runs at the
same checkpoint.

Three additions:
  1. `experience_kernels.cu`: drop the four `else if (eval_mode)` strict-argmax
     blocks; eval falls through to the existing Boltzmann path. Net -149 lines.
  2. `cuda_pipeline/mod.rs`: add `test_eval_action_select_boltzmann_bounded`,
     a focused unit test that exercises the kernel directly with peaked
     synthetic Q-values and asserts the histogram matches Boltzmann theory
     (P(best) ≈ 0.366, ≤ 0.6, ≥ 0.25). Runs in 1.65s after build, replaces
     15-min smoke runs for kernel-level validation.
  3. `trainers/dqn/trainer/metrics.rs`: log per-direction eval distribution
     (`val_dir_dist [short hold long flat]`) to HEALTH_DIAG. The kernel-side
     `dir_entropy` collapses Hold+Flat into one bucket, masking whether the
     eval policy actually picks one direction or balances Hold/Flat.

Verified: unit test produces histogram short=0.146 hold=0.239 long=0.382
flat=0.233 — matches Boltzmann math, confirms the eval kernel produces
diverse picks for peaked Q-input.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 19:28:42 +02:00
..