spec: Phase 2 regime awareness — ISV_DIM 8→12, cross-regime adaptation

4 new ISV signals: regime_velocity (d(ADX)/dt + d(CUSUM)/dt),
regime_disagreement (|norm_ADX - norm_CUSUM|), regime_transition_ema,
regime_stability (1 - sigmoid(5*velocity)).

Pearls: P4 regime velocity, P5 regime disagreement.
Gems: G4 regime-aware ISV, G5 soft regime mixture.
Novels: N6 cross-regime Mamba2 decay, N7 regime-conditioned gamma.

Tasks 10-13 added for Phase 2 implementation after core ISV.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-04-16 23:06:12 +02:00
parent a9f9b279f9
commit b0d67f0f8a

View File

@@ -690,7 +690,122 @@ Step 4 (`isv_signal_update`) is a standalone kernel launch — NOT captured in g
7. **Risk branch wider input** — change `w_risk_fc` in `compute_param_sizes` from `AH * SH2` to `AH * (SH2 + 9)`. Update `risk_budget_forward` + `risk_budget_backward` kernels for wider stride. Reallocate `risk_grad_buf`. Update `risk_aligned_count` and all `padded_byte_offset(param_sizes, 64)` callers.
8. **Recursive confidence head** — write `recursive_confidence_forward` kernel + MSE backward. Route `lagged_td_error_pinned` from `isv_signal_update` (copies slot [2] before overwrite).
9. **Weight tensors** — NUM_WEIGHT_TENSORS 68→78, extend `compute_param_sizes`, `xavier_init_params_buf`, `fan_dims`. Target network: ISV weights online-only (indices 68-77 NOT in target_params_buf).
10. **Graph recapture + smoke tests** — invalidate all graphs (`graph_forward = None`, `graph_adam = None`, `graph_forward_ddqn = None`). Run smoke test: `FOXHUNT_TEST_DATA=test_data/futures-baseline cargo test -p ml --lib -- test_generalization_components_smoke --include-ignored --nocapture`. Run compute-sanitizer: `compute-sanitizer --tool memcheck --print-limit 5 target/debug/deps/ml-* "test_generalization_components_smoke" --test-threads=1 --include-ignored`. **Target: 0 errors.** Run full test suite: `SQLX_OFFLINE=true cargo test -p ml --lib`. **Target: 899+ passed, 0 failed.**
10. **Graph recapture + smoke tests (Phase 1)** — invalidate all graphs, verify 0 errors.
11. **Regime ISV extension** — expand ISV_DIM 8→12. Add 4 regime signals to `isv_signal_update` (needs states_buf pointer). Update `isv_forward` w_fc1 from [16,8]→[16,12]. Update isv_history K*8→K*12, isv_decay 8→12.
12. **Regime-conditioned Mamba2 decay** — multiply Mamba2 decay by regime_stability (ISV slot [11]). Modify `mamba2_temporal_scan` kernel.
13. **Risk branch regime extension** — widen risk input from SH2+9→SH2+13. Update forward/backward kernels and w_risk_fc size.
14. **Final smoke test + compute-sanitizer (Phase 2)** — invalidate all graphs (`graph_forward = None`, `graph_adam = None`, `graph_forward_ddqn = None`). Run smoke test: `FOXHUNT_TEST_DATA=test_data/futures-baseline cargo test -p ml --lib -- test_generalization_components_smoke --include-ignored --nocapture`. Run compute-sanitizer: `compute-sanitizer --tool memcheck --print-limit 5 target/debug/deps/ml-* "test_generalization_components_smoke" --test-threads=1 --include-ignored`. **Target: 0 errors.** Run full test suite: `SQLX_OFFLINE=true cargo test -p ml --lib`. **Target: 899+ passed, 0 failed.**
---
## Phase 2: Regime Awareness Extension
The core ISV (Phase 1, tasks 1-9) makes the model aware of its own training dynamics. Phase 2 extends ISV with **market regime awareness** — the model learns to detect regime transitions and adapt its behavior during the most dangerous periods.
### The Problem
Markets don't have clean regime boundaries. ADX=25 could mean:
- **Entering a trend** (from 15) → direction branch should be aggressive
- **Leaving a trend** (from 40) → direction branch should be cautious
- **Consolidating** → prefer flat
Same value, three opposite strategies. The model currently sees WHERE it is but not WHERE it's GOING. Regime transitions are the most dangerous periods — the model's strategy for the previous regime is maximally wrong.
### Extension Architecture
Expand ISV from 8→12 signals. The 4 new slots are computed in `isv_signal_update` alongside the existing 8 — same kernel, same pure-GPU path. ISV encoder MLP input grows from 8→12 (hidden stays 16, output stays 8).
### New ISV Signals
| Slot | Signal | Formula | Source |
|------|--------|---------|--------|
| 8 | `regime_velocity` | `\|ADX[t] - ADX[t-1]\| + \|CUSUM[t] - CUSUM[t-1]\|` | States buffer, indices 40-41 |
| 9 | `regime_disagreement` | `\|norm(ADX) - norm(CUSUM)\|` | States buffer, normalized |
| 10 | `regime_transition_ema` | EMA of regime_velocity — detects sustained transitions vs noise | Derived from slot [8] |
| 11 | `regime_stability` | `1.0 - sigmoid(5 * regime_velocity)` — inverse of transition strength | Derived from slot [8] |
### PEARLS
**P4: Regime Velocity Features**
`d(ADX)/dt` and `d(CUSUM)/dt` computed as bar-over-bar differences. The rate of change tells the model whether regime indicators are stable, entering, or leaving. These are the single most informative regime features missing from the current system. Computed in `isv_signal_update` by reading the states buffer (one sample's ADX/CUSUM) and comparing to an EMA.
**P5: Regime Disagreement**
When ADX says "strong trend" but CUSUM fires a change signal, that's regime ambiguity. High disagreement = the model should be conservative. The risk branch sees this through ISV and reduces exposure automatically.
### GEMS
**G4: Regime-Aware ISV**
Regime uncertainty becomes an ISV signal. When `regime_velocity` is high (transition in progress), the ISV encoder outputs lower branch gate weights and shorter gamma. The model automatically becomes conservative during transitions — through learning, not hardcoded rules.
**G5: Soft Regime Mixture**
The `branch_confidence_routing` kernel already uses ISV gate × Q-confidence. With regime signals in ISV, this becomes a **continuous regime mixture** — the model can express "60% trending, 40% mean-reverting" through the softmax branch gates. This replaces the old binary regime classification.
### NOVELS
**N6: Cross-Regime Temporal Decay**
The Mamba2 temporal scan uses fixed exponential decay for h_s2 history. With regime awareness, the decay becomes **regime-conditioned**: during transitions, recent bars get exponentially more weight (faster forgetting of old-regime patterns). During stable regimes, longer history is preserved.
Implementation: multiply Mamba2 decay by `regime_stability` (ISV slot [11]):
```
effective_decay = base_decay * regime_stability
```
When stability=1 (stable regime), full history. When stability=0.3 (transition), rapid forgetting. The model learns to adapt its memory horizon to regime dynamics.
**N7: Regime-Conditioned Gamma (stacks with drift-conditioned)**
During regime transitions, far-future Q-values estimated under the old regime are unreliable. The gamma modulation from ISV already shortens horizon during drift — adding regime_stability to the gamma computation makes it respond to BOTH training dynamics AND market regime:
```
gamma_mod = 0.5 + 0.5 * sigmoid(w_gamma @ [ISV_embedding including regime])
```
No separate mechanism needed — regime signals flow through the same ISV encoder to the same gamma output. The model learns when to be myopic (high drift + regime transition) vs patient (stable training + stable regime).
### Implementation Changes
| Component | Change |
|-----------|--------|
| `ISV_DIM` | 8 → 12 |
| `isv_signal_update` kernel | Add 4 regime signal computations. Needs `states_buf` pointer + sample index for ADX/CUSUM. |
| `isv_forward` kernel | w_fc1 grows from [16,8] to [16,12]. Input temporal averaging over 12 dims. |
| Weight tensor [68] | w_isv_fc1 grows from 16*8=128 to 16*12=192 elements |
| `isv_history` buffer | K*8=32 → K*12=48 floats |
| `isv_decay` buffer | 8 → 12 learned weights |
| Mamba2 temporal scan | Multiply decay by `regime_stability` from ISV slot [11] |
| Risk branch input | SH2+9 → SH2+13 (4 more ISV signals) |
| Weight tensor [64] | w_risk_fc grows from AH*(SH2+9) to AH*(SH2+13) |
### Regime Signal Computation (in `isv_signal_update`)
The kernel needs access to ADX/CUSUM from the current batch. Since `isv_signal_update` runs after `reduce_current_q_stats` which has already processed the batch, the states buffer is available. Pass `states_buf` pointer and read sample 0's features as representative:
```cuda
/* [8] Regime velocity: |ΔADX| + |ΔCUSUM| */
float adx = states_ptr[0 * state_dim + 40]; /* sample 0 */
float cusum = states_ptr[0 * state_dim + 41];
float adx_delta = fabsf(adx - isv_signals[8]); /* previous ADX stored here */
float cusum_delta = fabsf(cusum - isv_signals[9]); /* previous CUSUM stored here */
/* Temporarily store raw values for next step's delta */
float prev_adx = isv_signals[8];
float prev_cusum = isv_signals[9];
isv_signals[8] = adx; /* will be overwritten with velocity below */
isv_signals[9] = cusum;
float regime_vel = adx_delta + cusum_delta;
isv_signals[8] = (1.0f - alpha) * prev_adx + alpha * regime_vel; /* velocity EMA */
/* [9] Regime disagreement: |normalized difference| */
float norm_adx = adx / fmaxf(fabsf(adx) + fabsf(cusum), 1e-6f);
float norm_cusum = cusum / fmaxf(fabsf(adx) + fabsf(cusum), 1e-6f);
isv_signals[9] = fabsf(norm_adx - norm_cusum);
/* [10] Regime transition EMA */
isv_signals[10] = (1.0f - alpha) * isv_signals[10] + alpha * regime_vel;
/* [11] Regime stability: 1 - sigmoid(5 * velocity) */
isv_signals[11] = 1.0f - 1.0f / (1.0f + expf(-5.0f * regime_vel));
```
Note: This requires passing `states_buf` pointer and `state_dim` to the kernel. Updated signature adds 2 parameters.
---
@@ -709,3 +824,7 @@ Step 4 (`isv_signal_update`) is a standalone kernel launch — NOT captured in g
| Recursive confidence may learn to always predict 0.5 (uninformative) | MSE loss with actual TD-error provides real supervision signal. If TD-errors vary, the head WILL learn to predict them. Early epochs: TD-error is high and variable → strong learning signal. |
| `regime_branch_gate` call sites must all be replaced | enumerate: `apply_regime_gate()`, `reduce_current_q_stats()`, `submit_forward_ops_ddqn()`. Replace with `branch_confidence_routing`. Drop `regime_gate_kernel` field. |
| Target network uses ISV weights | ISV weights are online-only (see Target Network section). Target forward uses neutral defaults (base_gamma, uniform gates). |
| ISV_DIM expansion 8→12 invalidates Phase 1 buffers | Phase 2 tasks reallocate isv_signals [12], isv_history [K*12], isv_decay [12]. w_isv_fc1 grows. Graph recapture required. |
| Regime signals from sample 0 only (not batch mean) | Sample 0 is representative for ADX/CUSUM which are market-level (same for all samples in a time window). For per-sample variation, the regime flows through h_s2 → branches already. |
| Regime-conditioned Mamba2 decay changes temporal context | Bounded by regime_stability ∈ [0, 1]. Stable regime: no change. Transition: faster decay (recent bars weighted more). Gradual — never drops to 0. |
| Risk branch input grows again SH2+9→SH2+13 | Same atomic update pattern as Phase 1. All offset callers updated together. |