feat(sp21): T3.1+T3.2 ISV defrost — wr_ema + hold_pct_ema (atomic)
SP21 Tier-3 foundation: defrost two production-frozen ISV slots that
pinned at 0 across every observed training epoch (d7bj7, xmd6b). Both
bugs in the same aggregator kernel, same structural shape: per-step
binary majority-vote indicators feeding fractional EMAs.
T3.1 — WR_EMA defrost (sp20_aggregate_inputs_kernel.cu):
- was: is_win_out = (2 * wins_count >= closed_count) ? 1 : 0
binary "majority won this step" indicator
- now: win_fraction_out = (float)wins_count / (float)closed_count
fractional in [0, 1]
- With actual val WR≈0.46, the binary signal was 0 most of the time,
pinning WR_EMA at 0 across 30+ epochs in xmd6b. EMA now converges
to population win rate.
T3.2 — HOLD_PCT_EMA defrost (same kernel, same pattern):
- was: action_is_hold_out = (hold_count * 2 > n_envs) ? 1 : 0
strict-majority indicator
- now: hold_fraction_out = (float)hold_count / (float)n_envs
- Cascade: HOLD_COST_SCALE controller compared hold_pct_ema=0 to
tgt±0.05, always saw < lower, ramped × 0.95 → clamped at floor
0.01 (the hold_cost_scale=0.0100 observation in d7bj7 logs).
T3.5 expected to cascade-fix in next training run.
- HOLD_REWARD_EMA gate preserves strict-majority semantic via
hold_fraction > 0.5f test in the consumer kernel.
Atomic across struct fields, kernel logic, Rust mirror, byte
serialization, doc tables, and 4 test files (per
feedback_no_partial_refactor):
- sp20_aggregate_inputs_kernel.cu (struct + 2 computations)
- sp20_emas_compute_kernel.cu (struct + reader + gate)
- sp20_aggregate_inputs.rs (doc table)
- sp20_emas_compute.rs (Rust struct + serialize + 3 tests)
- sp20_aggregate_inputs_test.rs (reader sig + 4 test assertions)
- sp20_emas_compute_test.rs (5 struct literal updates)
- sp20_phase1_4_wireup_test.rs (HOLD_PCT_EMA expected 0.625)
Verification:
- cargo check -p ml --tests: passes (warnings only)
- cargo test -p ml --lib sp20_emas: 6/6 unit tests pass
Pearl candidate: binary-majority aggregator over a fractional
underlying signal cannot serve as input to a fractional-target EMA.
The previous fix (commit 64bbbe418) addressed the per-bar vs segment
predicate at the producer site, but didn't notice the aggregator's
binarization step still collapsed the fraction to {0, 1}. Two bugs
in series, both now resolved.
Plan reference: docs/plans/2026-05-10-sp21-train-eval-coherence-isv-defrost.md
Tiers 3.3-3.6 remaining; T3.5 expected to cascade-fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,70 @@
|
||||
|
||||
**Status:** Populated during Plan 1 Task 6 (A.5 orphan audit). Updated on every commit per Invariant 7.
|
||||
|
||||
## 2026-05-10 — SP21 Tier-3 foundation: T3.1+T3.2 ISV defrost (wr_ema, hold_pct_ema)
|
||||
|
||||
**Branch:** `sp20-aux-h-fixed` (off `6df44e4c6`).
|
||||
**Commits:** 1 atomic (this commit).
|
||||
|
||||
Defrosts two production-frozen ISV slots that pinned-at-zero across all
|
||||
observed training epochs in d7bj7/xmd6b logs. Both bugs were in the same
|
||||
aggregator kernel (`sp20_aggregate_inputs_kernel.cu`), same structural
|
||||
shape: per-step binary majority-vote indicators feeding fractional EMAs.
|
||||
|
||||
**T3.1: WR_EMA — `is_win` → `win_fraction` (struct field rename + type change).**
|
||||
The aggregator computed `is_win_out = (2 * wins_count >= closed_count) ? 1 : 0`
|
||||
— a binary "majority of closed envs won" indicator. With actual val WR
|
||||
≈ 0.46 (xmd6b 30 epochs), the binary signal was 0 most of the time, and
|
||||
WR_EMA → 0 by Wiener-α floor blend. The aggregator now emits
|
||||
`win_fraction = wins_count / closed_count ∈ [0, 1]` and the EMA blends
|
||||
over the float directly. WR_EMA will converge to the population win rate.
|
||||
|
||||
**T3.2: HOLD_PCT_EMA — `action_is_hold` → `hold_fraction` (same fix shape).**
|
||||
The aggregator computed `action_is_hold_out = (hold_count * 2 > n_envs) ? 1 : 0`
|
||||
— strict-majority indicator. With actual hold pct in [0.10, 0.56],
|
||||
majority was rarely met, HOLD_PCT_EMA → 0. **Cascade**: the
|
||||
`HOLD_COST_SCALE` controller compares `hold_pct_ema` to `tgt ± 0.05` and
|
||||
ramps; with hold_pct_ema=0 it always saw `< lower` and ramped × 0.95
|
||||
every step → clamped at floor 0.01 (the `hold_cost_scale = 0.0100`
|
||||
observation in d7bj7 sp20_isv logs). Fixing T3.2 should cascade-fix
|
||||
T3.5 — verify in next training run. HOLD_REWARD_EMA gate preserves
|
||||
strict-majority semantic via `hold_fraction > 0.5f` test in the
|
||||
consumer kernel.
|
||||
|
||||
**Affected files (atomic per `feedback_no_partial_refactor`):**
|
||||
|
||||
- `crates/ml/src/cuda_pipeline/sp20_aggregate_inputs_kernel.cu` —
|
||||
struct fields, output computations.
|
||||
- `crates/ml/src/cuda_pipeline/sp20_emas_compute_kernel.cu` —
|
||||
struct fields, EMA reader, HOLD_REWARD_EMA gate.
|
||||
- `crates/ml/src/cuda_pipeline/sp20_aggregate_inputs.rs` — doc table.
|
||||
- `crates/ml/src/cuda_pipeline/sp20_emas_compute.rs` — Rust struct mirror,
|
||||
byte serialization, doc table, default-sentinel test, round-trip test.
|
||||
- `crates/ml/tests/sp20_aggregate_inputs_test.rs` — reader signature,
|
||||
4 fractional-comparison test assertions, 2 renamed test fns.
|
||||
- `crates/ml/tests/sp20_emas_compute_test.rs` — 5 struct-literal field
|
||||
renames (is_win → win_fraction, action_is_hold → hold_fraction).
|
||||
- `crates/ml/tests/sp20_phase1_4_wireup_test.rs` — HOLD_PCT_EMA expected
|
||||
value updated 1.0 → 0.625 (5/8 envs Hold).
|
||||
|
||||
**Verification:**
|
||||
|
||||
- `cargo check -p ml --tests` — passes (warnings only).
|
||||
- `cargo test -p ml --lib sp20_emas` — 6/6 unit tests pass, including
|
||||
`pack_inputs_round_trips` with `win_fraction: 0.46` + `hold_fraction: 0.0`.
|
||||
- GPU oracle tests gated `#[ignore = "requires GPU"]` — compile cleanly.
|
||||
|
||||
**Pearls applied / candidates:**
|
||||
|
||||
- `pearl_first_observation_bootstrap` — unchanged, both EMAs still bootstrap
|
||||
from sentinel.
|
||||
- `pearl_wiener_alpha_floor_for_nonstationary` — unchanged, α=0.4 floor.
|
||||
- New pearl candidate: **binary-majority aggregator over a fractional
|
||||
underlying signal cannot serve as input to a fractional-target EMA**.
|
||||
When the EMA is supposed to converge to a population fraction, the
|
||||
observation must itself be the fraction or a 0/1 sample, not a
|
||||
thresholded reduction.
|
||||
|
||||
## 2026-05-10 — REVERT: aux_horizon_update_kernel sp20-aux-h-fixed experiment closed
|
||||
|
||||
Reverts the forced-H=30 diagnostic that tested the bootstrap-failure hypothesis. **Hypothesis verdict: dead.** Across two epochs of `train-d7bj7`:
|
||||
|
||||
Reference in New Issue
Block a user