The compute_expected_q and quantile_q_select kernels read per_sample_support[i*3+0/1/2]
(3 floats per sample), but the experience collector was passing eval_v_range_ptr which
is only 2 floats (v_min, v_max). Every sample after sample 0 read out of bounds.
Replace the u64 pointer field with a proper CudaSlice<f32> buffer [alloc_episodes, 3]
that is tiled with [v_min, v_max, delta_z] once per epoch via update_per_sample_support().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two tests:
- test_generalization_kernels_load: no data, verifies all CUDA cubins load
- test_generalization_components_smoke: 3 epochs on fxcache, verifies
AdamW, cost_anneal, gamma_anneal, DSR, walk-forward state, Q-gap,
atom utilization, all kernel launches succeed, finite metrics.
Passes in 2.7s on RTX 3050 with 5000 bars.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HIGH: c51_loss_kernel now uses atom_positions per-branch in shmem_support
(was ignoring adaptive positions → forward/loss atom mismatch).
MEDIUM: adaptive_gamma wired into C51 Bellman projection via
set_adaptive_gamma(). Config gamma replaced with adaptive_gamma in
both launch_c51_loss sites.
MEDIUM: c51_grad z_norm uses adaptive atom positions when available
(was assuming linear grid for spread gradient).
LOW: adaptive_gamma field added to GpuDqnTrainer, initialized from
config, updated via passthrough from training loop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
G5: Ensemble variance gates magnitude Q-values via sigmoid scale.
High disagreement forces conservative (Small) position. Pinned
var_ema threshold — no cuMemcpy in hot path.
G6: 6-way cosine similarity penalty on branch hidden activations
(lambda=0.01). Informational — gradient integration deferred.
G10: Lipschitz penalty on Q-diffs between consecutive similar states
(lambda=0.005, threshold=0.95). Uses atomicAdd accumulation.
G14: Confidence-weighted PER flagged for follow-up (needs on-GPU
priority modification to avoid memcpy).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
G2: Transaction costs anneal 0%→100% over 20 epochs via pinned
device-mapped cost_anneal_ptr. No memcpy — CPU writes, GPU reads.
G15: Commitment penalty lambda=0.01, tau=5.0 bars. Also scales
with cost_anneal to ramp together.
G11: Per-branch Q-anchoring to neutral actions (Flat/Small/Market/Normal).
Focuses model capacity on alpha signal over doing nothing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
q_mean_scratch was CudaSlice with memcpy_dtoh readback every step.
Now pinned device-mapped: GPU writes via dev_ptr, CPU reads via
host_ptr directly. Dead inline EMA code removed, wired through
update_q_mean_ema(&self) method (DRY). No hot-path memcpy remains.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AdamW weight_decay was in kernel but hardcoded to 0.0 in launch.
Now uses config value (1e-4) gated by per-param mask (1.0 for trunk+value
indices 0-7, 0.0 for branches). L1 proximal step on w_s1 (first layer)
induces automatic feature selection from 42-dim input.
Also updates decision_transformer.rs Adam launch to match the new
3-arg kernel signature (uniform mask, L1 disabled).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reward rank normalization now operates on Sharpe contributions
(return - mean) / std instead of raw returns. Aligns reward signal
with Sharpe ratio goal. High-return trades during volatile periods
get lower rank weight than same return during calm periods.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9d: Q-mean EMA (alpha=0.01) tracks epoch-level drift. Drift penalty
(lambda=0.01) in c51_grad pushes Q-distribution back toward zero.
9e: 500-step LR warmup for Mamba2 and other new components. Prevents
gradient shock from new modules destabilizing trained trunk.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allocate rewards_5bar and rewards_20bar buffers [B] for future n-step
return computation. Wire multi_horizon_value_forward into training step
(currently degenerate d2d copy of 1-bar logits, ready for full GEMMs).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
atom_position_gradient kernel computes entropy-based gradient for
spacing_raw parameters. SGD decay toward uniform (lr=1e-3, every 50
steps) prevents atom positions from drifting. Concentrates atoms
where return distribution has mass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Primary goal: val/OOS Sharpe gap < 15%. If val_Sharpe drops to 25
post-generalization, OOS should be > 21. If val drops to 15, OOS > 13.
OOS Sharpe > 10 sustained as secondary target.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 extra value heads (W_v1/W_v2 pairs) for 5-bar and 20-bar horizons.
Regime-weighted blend: trend_weight=sigmoid((ADX-25)/5) mixes 1-bar
and 20-bar Q-values. Urgency branch learns temporal opportunity
structure. ~144K extra params. NUM_WEIGHT_TENSORS: 56 -> 64.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Walk-forward: strictly chronological, no future leakage.
Weight decay mask: indices 0-7 (trunk + value head), not just trunk.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ensemble_size was a dead config field — ensemble_count drives the
actual ensemble head count in fused_training.rs. Changed from 1 to 3
to actually enable 3 independent Q-network heads.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ensemble_size: 5 -> 3. Each head shares the trunk but has independent
branch weights. Ensemble variance replaces C51 aleatoric variance
for exploration: Q_select = Q_mean + sqrt(ensemble_var).
~174K extra params from triplicated branch heads.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
W_regime[4,4] + b_regime[4] produce softmax importance weights from
[ADX, CUSUM, Q_gap, atom_utilization]. Scales per-branch Q-values
so direction matters more in trends, magnitude matters more in ranges.
NUM_WEIGHT_TENSORS: 50 -> 52.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Task 9d: Q-mean EMA drift penalty (lambda=0.01) in C51 grad kernel.
Prevents +0.47 Q-mean drift observed in train-vpb4w.
Task 9e: 500-step LR warmup for new tensor groups (regime gate,
adaptive atoms, Mamba2, multi-horizon). Prevents gradient shock
on new components introduced to trained network.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three new GPU kernels for OOS performance enhancement:
- regime_branch_gate: learned per-branch importance weights from regime features
- adaptive_atom_positions: softmax-normalized learnable C51 atom spacing
- mamba2_temporal_scan + mamba2_update_history: selective SSM for temporal context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Task 9a: Adaptive atom position training via atom entropy gradient.
Numerical finite-difference gradient on spacing_raw, SGD at LR=1e-3.
Task 9b: Mamba2 BPTT backward through K=8 scan steps.
d_W_A/B/C accumulated, separate Adam at LR=1e-4.
Task 9c: Multi-horizon C51 loss — 3 n-step passes (1/5/20 bar),
3 C51 loss launches, regime-weighted gradient blend (ADX-based).
Fixes the "untrained component" gap identified in plan review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
train-w2z55 rewound to epoch 0 (improvement_rate=17.3, val_Sharpe=17.3)
instead of epoch 20 (improvement_rate=0.4, val_Sharpe=45.4). The model
lost ALL learned behavior and couldn't re-learn at low cosine LR.
Fix: sort checkpoints by val_Sharpe (highest first). Rewind targets the
BEST state (val_Sharpe=45), not the fastest-climbing moment (epoch 0).
Added val_sharpe field to TrajectoryCheckpoint for proper ranking.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Observed in train-w2z55: rewind to epoch 0 weights at epoch 30, but
cosine LR at t_local=10 (50% decay). Model couldn't re-learn at low LR.
val_Sharpe stuck at 17.39 for 4+ epochs after rewind.
Fix: cosine_epoch_offset set to current epoch on rewind.
t_local = (epoch - offset) % T_restart = 0 after rewind → full LR.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ROOT CAUSE: run_backtracking_epoch_end received epoch_sharpe (training
Sharpe from experience collection, ~0.65-0.79 oscillating) instead of
val_Sharpe (deterministic backtest, 33.49 frozen for 56 epochs).
Training Sharpe oscillates even when the model is frozen → sharpe_frozen
was always false → AND condition never met → backtracking never triggered
despite 56 consecutive frozen epochs in train-2tgs7.
Fixes:
1. Pass val_sharpe (-val_loss) to run_backtracking_epoch_end
2. prev_val_sharpe field on BacktrackingState (not sharpe_history)
3. improvement_rate uses val_Sharpe delta (not training Sharpe)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Checkpoint save: improvement_rate used sharpe_history.last() which is
the CURRENT epoch (just pushed). Always compared current to itself → 0.
Fix: use sharpe_history[len-2] (previous epoch).
2. Branch Adam reset: required !checkpoints.is_empty() but branch reset
doesn't USE checkpoints — it just zeros momentum in-place. Removed
the checkpoint guard so the lightweight fix fires even without saved
checkpoints.
Both bugs prevented backtracking from ever acting in train-l7g9t despite
detecting 6 consecutive frozen epochs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stable Q-gap + rising val_Sharpe is healthy convergence, not a plateau.
OR logic would fire branch Adam reset at epoch ~12 when Q-gap stabilizes
at 0.318 while val_Sharpe climbs 17→40. AND requires BOTH Q-gap frozen
AND val_Sharpe stagnating — true plateau, nothing improving.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
states_buf has stride pad128(state_dim) for CUTLASS alignment. The
concat_ofi kernel was reading with stride state_dim → OOB for sample 1+.
With state_dim=50, pad=128: sample 1 OFI at offset 128+42=170, but
kernel read at 50+42=92 (sample 0 padding area). Silent data corruption.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adam kernel changed from float lr to const float* lr_ptr. The CUDA graph
captures the pointer (not the value). CPU writes new LR to lr_pinned each
epoch, kernel reads current value on replay. Eliminates 30s × 200 = 100 min
graph recapture overhead from cosine LR warm restarts.
Selectivity and denoiser Adam launchers share aux_lr_pinned (fixed 1e-4)
to satisfy the updated const float* kernel signature without graph impact.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Denoiser: q_denoise_backward kernel computes MSE gradient vs target
network Q-values, backprops through 2 FC-SiLU-FC steps. Separate Adam
at LR=1e-4. Runs after main backward in training step.
xLSTM: qlstm_train_step kernel computes prediction loss (context[0]
vs prev_q_mean), backprops through output gate + retrieval. SGD update
in-place at LR=1e-4. Runs after qlstm_step in reduce_current_q_stats.
Both fully on GPU. Zero untrained components remaining.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Renamed: q_bf16→q_host, bf16_uniform→uniform, host_bf16→host,
bf16_raw→raw, bf16_pred→pred, raw_bf16_ptr→raw_f32_ptr (removed dup).
Removed stale comments: "no bf16 NaN risk", "no bf16 overflow",
"no bf16 precision loss", "BF16 bias+relu kernels".
Removed redundant .to_vec() clones from test helpers.
Also includes precommit fixes:
- CRITICAL: backward_full uses padded_byte_offset for ALL offsets
- HIGH: Graph + xLSTM params documented as fixed-init by design
- LOW: Diffusion denoiser K=3→K=2 (eliminates ping-pong copy)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CRITICAL: backward_full manual offset calculations replaced with
padded_byte_offset for ALL 24 tensor offsets. Eliminates brittle
manual computation that was a regression risk.
HIGH: Graph message passing + xLSTM params documented as fixed-init
by design. Graph edges encode domain knowledge. xLSTM context is
a learned-at-init projection. Training deferred to future work.
LOW: Diffusion denoiser changed from 3 to 2 steps (eliminates
ping-pong DtoD copy). raw_bf16_ptr removed (dead code).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
liquid_tau_rk4_step kernel: adaptive Euler/RK4 based on xLSTM context norm.
per_branch_q_gap_ema and liquid_mod moved from pinned/CPU to CudaSlice device buffers.
Zero CPU compute in training dynamics. Zero pinned memory for liquid tau.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8 cubic B-spline basis functions per gate neuron + residual connection.
Spline coefficients initialized to uniform 0.125 (flat 0.5 gate).
kan_gate_combine replaces glu_combine in forward.
kan_gate_backward replaces glu_backward in backward.
9,216 new parameters (4 x AH x 9).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>