From 9a10e82fa7f76e4fa070869f8a2b83a5dfa73e19 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Fri, 6 Mar 2026 13:10:27 +0100 Subject: [PATCH] fix(ml): disable val-loss early stopping in hyperopt, fix penalty metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sharpe-based early stopping kills every hyperopt trial at epoch 4 because compute_epoch_financials() is deterministic (greedy argmax on fixed validation data) — the model doesn't change enough in 8 short epochs to shift any argmax decisions, making Sharpe bit-identical across epochs and triggering plateau detection immediately. Co-Authored-By: Claude Opus 4.6 --- crates/ml/src/hyperopt/adapters/dqn.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/ml/src/hyperopt/adapters/dqn.rs b/crates/ml/src/hyperopt/adapters/dqn.rs index 8a9104c33..271d60d31 100644 --- a/crates/ml/src/hyperopt/adapters/dqn.rs +++ b/crates/ml/src/hyperopt/adapters/dqn.rs @@ -2352,10 +2352,12 @@ impl HyperparameterOptimizable for DQNTrainer { min_replay_size: params.batch_size * 2, // Need at least 2x batch size epochs: self.epochs, checkpoint_frequency: (self.epochs / 5).max(1), // Save 5 checkpoints per trial, min 1 - // C4 FIX: Re-enable early stopping with adaptive plateau window. - // Previous issue: plateau_window=5 with 8 epochs triggered too often. - // Fix: adaptive window = max(epochs / 2, 3), giving enough learning time. - early_stopping_enabled: true, + // C4: Disable early stopping for hyperopt. The Sharpe-based plateau + // detector fires every trial because compute_epoch_financials() is + // deterministic (greedy argmax on fixed validation data) and the model + // doesn't change enough in 8 short epochs to shift any argmax decisions, + // so Sharpe is bit-identical across epochs → plateau at window boundary. + early_stopping_enabled: false, q_value_floor: -5.0, min_loss_improvement_pct: 2.0, plateau_window: (self.epochs / 2).max(3),