2.9 KiB
2.9 KiB
GPU-Native Validation + H100 Performance Optimizations
Goal
Replace the CPU validation path with the existing GpuBacktestEvaluator, delete all dead CPU code, and apply remaining performance optimizations to push epoch time from 15.6s toward <5s.
Architecture
The training loop's compute_validation_loss() in metrics.rs currently:
- Assembles states on CPU (
Vec<f32>) - Uploads to GPU (
clone_htod_f32_to_bf16) - Runs cuBLAS forward (
compute_q_values) - Downloads Q-values to CPU (
dtoh_bf16_to_f32) — 2s sync - CPU argmax over Q-values
- CPU PnL computation
- CPU Sharpe ratio
Steps 4-7 are pure CPU with a mandatory GPU→CPU sync. The GpuBacktestEvaluator (2086 lines, gpu_backtest_evaluator.rs) already does all of this on GPU — used by hyperopt adapters but NOT by the training loop.
Changes
1. Wire GpuBacktestEvaluator into Training Loop
- Add
gpu_evaluator: Option<GpuBacktestEvaluator>field toDQNTrainer - Initialize in constructor from validation data +
DqnBacktestConfig - Replace
compute_validation_loss()body: callgpu_evaluator.evaluate_dqn_graphed()with current weights, extractWindowMetrics.sharpe - The evaluator pre-uploads validation data to GPU once at construction (not per epoch)
2. Delete Dead CPU Validation Code
Remove from DQNTrainer:
val_features_gpu: Option<Vec<f32>>field + lazy initval_closes_gpu: Option<(Vec<f32>, Vec<f32>)>field + lazy initval_ofi_gpu: Option<Vec<f32>>field + lazy init- CPU state assembly loop (lines 485-509 in metrics.rs)
clone_htod_f32_to_bf16calldtoh_bf16_to_f32readback- CPU argmax loop (lines 535-555)
- CPU Sharpe computation (lines 568-584)
- All associated
useimports
3. BF16 Backward TF32
Change batched_backward.rs:
- 2 GEMMs from
CUBLAS_COMPUTE_32F→CUBLAS_COMPUTE_32F_FAST_TF32 - Both activation gradient (BF16→BF16) and weight gradient (BF16→F32) paths
- TF32's 10-bit mantissa is sufficient for gradients (Adam momentum smooths noise)
4. Training Loop Optimizations (already in working tree)
- Vaccine sample only every 10th step (was: every step, wasting 43ms)
- Training guard every 5th step (was: every step, 12ms overhead)
- Single write lock for sample+step (was: read→write cycling, 43ms contention)
- Causal intervention interval 10→50
- Remove all H100_DIAG tracing::info
Expected Impact
| Optimization | Per-epoch savings |
|---|---|
| GPU-native validation (2s CPU → 50ms GPU) | -1.95s |
| BF16 backward TF32 (2-3x GEMM throughput) | -3-5s |
| Single-sample + guard + lock | -3.6s |
| Total estimated | ~8-10s |
| Target epoch time | ~5-7s |
Testing
- Smoke tests: verify Sharpe computation matches between old CPU path and new GPU evaluator (within BF16 tolerance)
- H100 deployment: confirm epoch timing improvement
- Loss convergence: verify training quality unchanged