From e9e2e87a64f1b39aa04fae26d1fe903cc197feaf Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sun, 29 Mar 2026 17:22:16 +0200 Subject: [PATCH] =?UTF-8?q?fix(hyperopt):=20max=5Fsteps=5Fper=5Fepoch=20by?= =?UTF-8?q?=20GPU=20tier,=20adam=5Fepsilon=201e-3=E2=86=921e-8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hyperopt adapter now sets max_training_steps_per_epoch: RTX 3050 (≤40GB) = 200 steps, H100 (≥40GB) = 2000 steps. Without this, each trial trained the full dataset (2917 steps/epoch) making hyperopt 11x slower than necessary on local GPU. - adam_epsilon default 1e-3→1e-8 everywhere (conservative(), DQNConfig). The old 1e-3 was a BF16 workaround (bf16(1e-8)=0 → div-by-zero). Adam is now f32, so standard 1e-8 is correct. - Early stopping enabled in dqn-localdev.toml (patience=20). Hyperopt: 2 trials × 5 epochs in 132s (was ~20min). Zero NaN. Co-Authored-By: Claude Opus 4.6 (1M context) --- config/training/dqn-localdev.toml | 2 +- crates/ml-dqn/src/dqn.rs | 8 ++++---- crates/ml/src/hyperopt/adapters/dqn.rs | 4 ++++ crates/ml/src/trainers/dqn/config.rs | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/config/training/dqn-localdev.toml b/config/training/dqn-localdev.toml index db55d4fb8..66d371bc1 100644 --- a/config/training/dqn-localdev.toml +++ b/config/training/dqn-localdev.toml @@ -32,7 +32,7 @@ buffer_size = 10000 min_replay_size = 100 [early_stopping] -enabled = false +enabled = true patience = 20 min_epochs_before_stopping = 50 diff --git a/crates/ml-dqn/src/dqn.rs b/crates/ml-dqn/src/dqn.rs index 7bb733ee1..c65f42948 100644 --- a/crates/ml-dqn/src/dqn.rs +++ b/crates/ml-dqn/src/dqn.rs @@ -325,7 +325,7 @@ impl Default for DQNConfig { // Agent-level trading parameters minimum_profit_factor: 1.5, // BUG #7 FIX: 50% margin above breakeven weight_decay: 1e-4, // WAVE 30: Standard L2 regularization strength - adam_epsilon: 1e-3, // BF16-safe: bf16(1e-8)=0 + adam_epsilon: 1e-8, // f32 Adam (master weights are f32) dropout_rate: 0.0, // Disabled by default; hyperopt wires from dropout_initial // Mixed precision: disabled by default (auto-detected at runtime) @@ -610,7 +610,7 @@ impl DQNConfig { minimum_profit_factor: 1.5, weight_decay: 1e-4, - adam_epsilon: 1e-3, // BF16-safe: bf16(1e-8)=0 + adam_epsilon: 1e-8, // f32 Adam (master weights are f32) ..Default::default() } @@ -677,7 +677,7 @@ impl DQNConfig { minimum_profit_factor: 2.0, // Higher safety margin for conservative config weight_decay: 1e-4, - adam_epsilon: 1e-3, // BF16-safe: bf16(1e-8)=0 + adam_epsilon: 1e-8, // f32 Adam (master weights are f32) ..Default::default() } @@ -769,7 +769,7 @@ impl DQNConfig { minimum_profit_factor: 1.5, weight_decay: 1e-4, - adam_epsilon: 1e-3, // BF16-safe: bf16(1e-8)=0 + adam_epsilon: 1e-8, // f32 Adam (master weights are f32) dropout_rate: 0.0, } diff --git a/crates/ml/src/hyperopt/adapters/dqn.rs b/crates/ml/src/hyperopt/adapters/dqn.rs index 1da62578f..3fa675340 100644 --- a/crates/ml/src/hyperopt/adapters/dqn.rs +++ b/crates/ml/src/hyperopt/adapters/dqn.rs @@ -2700,6 +2700,10 @@ impl HyperparameterOptimizable for DQNTrainer { // medium GPUs (16-24GB) where optimal_n_episodes might not kick in. gpu_n_episodes: if budget.gpu_memory_mb >= 40960 { 512 } else { 128 }, gpu_timesteps_per_episode: 500, + // Cap steps/epoch by GPU tier: RTX 3050 = fast iteration, H100 = full quality. + // Without this, the default (0=unlimited) trains on the entire dataset per epoch, + // making each hyperopt trial ~10min on RTX 3050 instead of ~30s. + max_training_steps_per_epoch: if budget.gpu_memory_mb >= 40960 { 2000 } else { 200 }, avg_spread: 0.0001, // GPU-dynamic network sizing (from hyperopt search space) diff --git a/crates/ml/src/trainers/dqn/config.rs b/crates/ml/src/trainers/dqn/config.rs index 9aa944073..dee50c302 100644 --- a/crates/ml/src/trainers/dqn/config.rs +++ b/crates/ml/src/trainers/dqn/config.rs @@ -1503,7 +1503,7 @@ impl DQNHyperparameters { // WAVE 30: L2 Weight Decay weight_decay: 1e-4, // Default: 0.0001 (standard regularization strength) - adam_epsilon: 1e-3, // BF16-safe + adam_epsilon: 1e-8, // f32 Adam (master weights are f32) // Conservative Q-Learning (CQL) cql_alpha: 0.1, // Default: mild conservatism (0.1 of 0.0-1.0 range) @@ -1713,7 +1713,7 @@ pub(crate) fn dqn_default_config() -> DQNConfig { minimum_profit_factor: 1.5, weight_decay: 1e-4, - adam_epsilon: 1e-3, // BF16-safe + adam_epsilon: 1e-8, // f32 Adam (master weights are f32) ..Default::default() } }