Commit Graph

17 Commits

Author SHA1 Message Date
jgrusewski
904185004c feat: L40S GPU profile + auto-derive cuda-compute-cap from GPU pool
argo-train.sh now auto-selects cuda-compute-cap based on --gpu-pool:
  - ci-training-h100* → sm_90 (Hopper)
  - ci-training-l40s  → sm_89 (Ada Lovelace)

Added config/gpu/l40s.toml:
  - batch_size=4096 (between H100's 8192 and A100's 2048)
  - buffer_size=300K (scaled for 48GB VRAM)
  - gpu_timesteps_per_episode=2000 (bandwidth-limited)
  - gpu_n_episodes=2048 (scaled from H100's 4096)

GPU profile loader maps "L40S" → "l40s" (was "a100" fallback).

Also fixed pre-existing test drift: num_atoms=52 in h100.toml/a100.toml
was 51 in test expectations (padding alignment for C51 kernels).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:59:06 +02:00
jgrusewski
6dd1aeca7e perf: disable replay buffer VRAM auto-sizing — cap at 500K entries
Auto-sizer inflated replay buffer to 15.8M entries on H100 (45% of 80GB VRAM).
The PER prefix scan inside the CUDA graph processes ALL 15.8M entries every step,
dominating step time. With buffer_size=500K, the scan processes 500K entries instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 09:20:15 +02:00
jgrusewski
c2edb273ca perf: batch_size 16384 → 8192 — 2x faster GEMMs, more frequent updates
At 16384, each GEMM saturates 97% of 132 SMs — no room for multi-stream
parallelism. At 8192, GEMMs use ~50% SMs, allowing branch streams and
aux parallelism to fill idle SMs. 2x more steps/epoch but each ~2x faster.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 09:01:34 +02:00
jgrusewski
b4cf279b73 fix: reduce H100 replay buffer VRAM fraction 55% → 45% — OOM from IQN 8.6GB + Phase 2
IQN with 64 quantiles × batch=16384 allocates 8.6GB for tiled intermediates.
Combined with attention (250MB), Phase 2 aux workspaces (64MB), backward
branch scratch (16MB), the 55% replay fraction left only 349MB free —
not enough for experience collector's 192MB next_states allocation.

45% frees ~8GB headroom: replay buffer 19.4M → ~15.9M (still 60× batch).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 18:42:06 +02:00
jgrusewski
709fffe923 fix: revert c51_loss_reduce to (1,1,1) — same Hopper graph hang class
The warp-parallel (32,1,1) change to c51_loss_reduce caused the same
hang as isv_feature_gate: changing block_dim inside graph_mega alters
CUDA Graph node structure on Hopper's TMA scheduler. Must stay (1,1,1).

Also: batch_size 8192→16384, gpu_n_episodes 1024→4096, num_atoms 51→52
to align h100.toml with dqn-production.toml.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:46:15 +02:00
jgrusewski
f1be4619e0 fix: H100 VRAM fraction 0.70→0.55 — OOM with state_dim=96 + 86 tensors
batch_size auto-scaled to 16384 consuming 78GB, leaving only 3GB
for experience collector → OOM. Reducing replay buffer fraction
gives more headroom. state_dim grew 88→96 (plan features), weight
tensors grew 68→86 (ISV + plan head).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 09:23:51 +02:00
jgrusewski
c74a687ea8 feat: position-gated episodes + 5000-bar limit — close 45x training/val gap
Episode done flag: timer-based -> position-gated (trade complete = done).
V(flat)=0 is correct terminal anchor. Soft reset keeps equity on
trade completion; hard reset only on data-end or capital breach.
H100: 100 bars -> 5000 bars, gpu_n_episodes -> 1024.
ExperienceProfile gains optional gpu_n_episodes field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:56:44 +02:00
jgrusewski
cf442ff317 fix: restore explicit buffer_size in GPU profiles (auto-sizing removed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:24:19 +02:00
jgrusewski
833cc07d0e fix: training profile must not override GPU profile batch_size
dqn-production.toml batch_size=8192 was overriding GPU profile batch_size=64
on RTX 3050 via apply_to(), causing OOM/hang. GPU profile is the sole
authority for batch_size — training profile controls learning params only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 23:42:12 +02:00
jgrusewski
8c75665722 fix: restore cached_n_episodes field lost in merge + batch_size=128 for RTX 3050
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 23:29:04 +02:00
jgrusewski
f5b21406a8 fix: restore batch_size to GPU profiles — profile defaults, not auto-scaling
Auto-scaling returned 8192 on 4GB RTX 3050 (should be 64), causing
17s/epoch instead of 0.28s. The VRAM math didn't account for IQN (1.1GB),
attention, IQL, replay buffer (70% VRAM).

Profile-tested values:
- RTX 3050: 64 (4GB, minimal)
- A100: 2048 (40-80GB)
- H100: 8192 (80GB, production)
- Default: 256 (conservative)

Auto-scaling remains as fallback for batch_size=0 (unknown GPU).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:26:24 +02:00
jgrusewski
5546a45bc3 refactor: remove gpu_n_episodes override — auto-scale from VRAM everywhere
gpu_n_episodes was manually overridden in GPU profiles, training configs,
test files, and hyperopt — all set to 0 or small fixed values that
bypassed the auto-scaling logic, causing a div-by-zero crash in
train_baseline_rl.

Now: single auto-scaling path via optimal_n_episodes() from VRAM/SM
count. No manual override field. Cap at 16384 (consistent with
AutoBatchSizer's 8192 cap pattern). Floor at 32 for small GPUs.

Removed gpu_n_episodes from:
- DQNHyperparameters, PpoHyperparameters structs
- All 4 GPU profiles (rtx3050, h100, a100, default)
- Training profiles (smoketest, localdev)
- ExperienceProfile struct + serde
- Hyperopt adapter
- All test overrides

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:21:45 +02:00
jgrusewski
12fdd18223 refactor: remove entire CPU training path — 5,307 lines of dead code
Deleted:
- DQN::compute_loss_internal (280 lines) — old Candle forward+loss
- DQN::train_step (55 lines) — old Candle training step
- DQN::compute_gradients (47 lines) — old gradient accumulation
- ComputeLossResult struct — only used by deleted functions
- RegimeConditionalDQN::train_step (65 lines) — old dispatch
- RegimeConditionalDQN::train_step_gpu_regime (100 lines) — old GPU path
- RegimeConditionalDQN::compute_gradients_gpu (130 lines) — old regime gradients
- RegimeConditionalDQN::compute_gradients (92 lines) — old dispatch
- DQNAgentType::train_step dispatch — dead
- DQNAgentType::compute_gradients dispatch — dead
- GpuDqnTrainer::upload_batch (71 lines) — old CPU→GPU upload
- train_step.rs (500 lines) — entire module including ensure_fused_ctx
- dqn_benchmark.rs — used old train_step
- examples.rs — used old train_step
- validation/adapters.rs (289 lines) — used old train_step
- dqn/trainable_adapter.rs — used old train_step
- gpu_smoketest.rs — tested old train_step
- Gradient accumulation path in training_loop.rs (144 lines)
- IQN d_h_s2().clone() → raw pointer (zero alloc)
- Causal intervention format! string alloc removed
- Dead HER relabel functions (320 lines)

Kept:
- ensure_fused_ctx logic inlined into training_loop.rs
- set_noise_sigma_scale re-added to RegimeConditionalDQN

Fixed:
- GpuReplayBuffer max_batch_size wired from batch_size parameter
  (was hardcoded 1024, blocking batch_size=8192)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 09:06:23 +02:00
jgrusewski
5363185721 perf: dynamic batch sizing — AutoBatchSizer drives batch_size on H100
Set batch_size=0 in config/gpu/h100.toml as sentinel for auto-compute.
The constructor now treats batch_size==0 as "let AutoBatchSizer drive":
it uses the VRAM-computed ceiling capped at 8192, instead of the static
1024 that was wasting >90% of H100's 80GB VRAM bandwidth.

Previously AutoBatchSizer computed the optimal batch (e.g. 2085808) but
the profile's batch_size=1024 always won. Now with batch_size=0 the
sizer's result flows through, enabling full SM occupancy on H100.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 22:08:01 +02:00
jgrusewski
6e40e86c09 perf: constrain hyperopt search space + increase H100 experience episodes
Hyperopt:
- num_atoms: 51-201 → 11-51 (GPU profile caps to hardware limit)
- hidden_dim_base: 256-1024 → 128-512 (1024+ is wasteful for 2-layer net)
- Prevents wildly oversized networks (num_atoms=200 caused 25s/epoch)

H100 experience:
- gpu_n_episodes: 256 → 2048 (8x larger cuBLAS batch saturates 132 SMs)
- gpu_timesteps_per_episode: 500 → 100 (fewer steps, more parallel episodes)
- Total experiences: 204K/epoch (was 128K) with better GPU utilization
- Expected: experience 357ms → ~100ms (SM utilization 5% → 40%+)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 01:40:16 +01:00
jgrusewski
e4b7d2ffb0 feat: GPU TOML profile system — remove ALL hardcoded VRAM if/else chains
Created config/gpu/{default,rtx3050,h100,a100}.toml with all GPU-specific
parameters: batch_size, num_atoms, buffer_size, hidden_dim_base,
replay_buffer_vram_fraction, gpu_n_episodes, gpu_timesteps_per_episode,
cuda_stack_bytes.

GpuProfile::load() auto-detects GPU by device name, falls back to
embedded defaults (include_str!). Override via FOXHUNT_GPU_PROFILE env.

Removed dead code:
- detect_vram_mb(), vram_scaled_hidden_dims(), vram_scaled_base_dim(),
  resolve_hidden_dim_base() + 18 tests for these functions

All callers updated: train_baseline_rl, DQNTrainer constructor,
PPO trainer, smoke tests, pipeline tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:39:40 +01:00
jgrusewski
8a68bdf21d feat: GPU TOML profile system — replace hardcoded VRAM if/else chains
Replace scattered VRAM-based if/else chains with a declarative TOML profile
system. GPU profiles (rtx3050, a100, h100, default) are selected by device
name and embedded at compile time via include_str! for zero-filesystem
fallback in CI/containers, with filesystem and env var overrides.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:21:55 +01:00