2 Commits

Author SHA1 Message Date
jgrusewski
4e21c38b85 fixup(sp20): Phase 1.1 K=3 → K=2 retarget (production aux head is K=2)
The Phase 1.1 sp20_stats_compute kernel (de922c6a4) assumed the SP14-C aux
head emits 3-class logits {short, hold, long} with baseline 1/3. This was
an error in the SP19+20 spec — production aux head emits K=2 logits
{down, up} per gpu_aux_heads.rs:61 (AUX_NEXT_BAR_K = 2, established by
SP13 B1.1a). Wiring K=2 production aux into the K=3 kernel = OOB reads +
corrupt stats.

Retargets the kernel + launcher + tests to K=2 atomically per
feedback_no_partial_refactor:

- Kernel: SP20_K_CLASSES 3→2; SP20_UNIFORM_K3 0.333…→SP20_UNIFORM_K2 0.5f;
  Pass A reads 2 logits (was 3); aux_conf range [0, 1/2] (was [0, 2/3]).
- Launcher: AUX_K_CLASSES 3→2; renamed unit test
  aux_k_classes_is_three → aux_k_classes_matches_production_aux_head.
- Tests: rewrote CPU oracle for K=2 input shape and 0.5 baseline; updated
  expected p50/std ranges; redesigned heterogeneous-distribution test to
  use ramped (not lockstep) clusters — K=2's saturated softmax in the hot
  half collapses every row to bin 255, triggering the
  pearl_sp4_histogram_warp_tile_undercount trap; ramped clusters distribute
  bin indices across each warp's 32 lanes so the histogram path matches
  the CPU oracle within bin_width tolerance.

Phase 1.2 (sp20_emas_compute) and Phase 1.3 (sp20_controllers_compute)
consume the scalar [p50, std] outputs and do NOT carry the K dimension.
Both regression suites verified passing unmodified:
- sp20_emas_compute_test: 4 GPU + 1 unit, all pass.
- sp20_controllers_compute_test: 7 GPU, all pass.

Verification (RTX 3050 Ti, sm_86):
- sp20_stats_compute_test: 4 GPU oracle + 4 launcher unit, all pass.
- cargo check -p ml --features cuda: clean (pre-existing warnings only).

Spec + plan amended at top with "AMENDED 2026-05-09" notes; audit doc
Phase 1.1 entry has a "K=2 fixup" subsection documenting the change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:46:17 +02:00
jgrusewski
de922c6a4a feat(sp20): Phase 1.1 sp20_stats_compute kernel
Component 5 / Kernel 3 of the SP20 fused-producer chain. Single-block
BLOCK=256 kernel reads `aux_logits [B, 3]` (the SP14-C aux head's
3-class direction logits) and emits `[aux_conf_p50, aux_conf_std]`
into a `MappedF32Buffer<2>`, where the per-row signal is
`aux_conf[i] = max_c softmax(logits[i, *])[c] - 1/3`.

p50 uses the inlined `sp4_histogram_p99` pattern (per-warp tile
binning + cumulative-from-bottom, no atomicAdd per
`feedback_no_atomicadd`); std uses two block tree-reductions sharing
one shmem tile sequentially. One fused kernel streams `aux_logits`
once for both stats per `pearl_fused_per_group_statistics_oracle`.

Phase 1.4 wires the production launch site atomically with the rest
of the SP20 reward chain per `feedback_no_partial_refactor`. This
commit lands kernel + Rust launcher + GPU oracle tests + build entry
+ audit-doc entry together so the kernel is independently verifiable
on RTX 3050 Ti (sm_86) and L40S (sm_89) before the EMA + controller
producers (Phase 1.2 + 1.3) reference its outputs.

Tests verify:
  - uniform logits → aux_conf = 0 → [p50, std] = [0, 0]
  - varied confidence (logit ramp 0 → 3) → matches CPU oracle
  - heterogeneous half-hot half-uniform → matches CPU oracle
  - empty batch → degenerate-guard writes [0, 0]

All 4 GPU oracle tests + 4 launcher unit tests pass on RTX 3050 Ti.
Test data uses per-row variance to avoid the
`pearl_sp4_histogram_warp_tile_undercount` lockstep-uniform trap
(concentrated values within one bin_width race the per-warp
non-atomic increments).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 18:43:11 +02:00