fix: recalibrate CI tests for wider v_range (±240) and larger gradients

dqn-smoke: Walk-forward validation DQN uses raw price returns (~0.001),
not production reward_scale=10. Set v_min/v_max to ±10 for the small
16-dim 3-action test network (was inheriting ±240 from production default).

dqn-early-stop: Gradient collapse threshold = lr × multiplier must exceed
the actual gradient norm to trigger collapse. With v_range ±240, gradient
norms reach 100-10000 (was ~0.5-2.0 with old ±2.0 range). Updated
multiplier from 1e9 to 1e12 to guarantee threshold (10000) > grad norm.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-03-25 21:30:11 +01:00
parent 69415f1a97
commit 83b089928c
2 changed files with 12 additions and 9 deletions

View File

@@ -138,14 +138,12 @@ async fn test_early_stopping_terminates_with_error() {
ml::training_profile::DqnTrainingProfile::load("dqn-smoketest").apply_to(&mut hyperparams);
// Force gradient collapse detection by setting threshold above typical grad norm.
// Threshold = 1e-8 × 1e9 = 10.0 (always above typical grad norms ~0.5-2.0).
// RegimeConditionalDQN tracks collapse across epoch-boundary log_diagnostics()
// and per-step check_gradient_collapse() with a shared counter.
// With patience=3, collapse triggers during epoch 2 training steps
// (epoch 1 boundary increments to 1, per-step checks in epoch 2 reach 3).
// Threshold = lr × multiplier. With v_range ±240 (C51), gradient norms can reach
// 100-10000 depending on epoch/data. Set threshold = 1e-8 × 1e12 = 10000.0 to
// guarantee the norm stays below threshold → collapse triggers reliably.
hyperparams.learning_rate = 1e-8;
hyperparams.epochs = 10;
hyperparams.gradient_collapse_multiplier = 1e9;
hyperparams.gradient_collapse_multiplier = 1e12;
hyperparams.gradient_collapse_patience = 3;
hyperparams.min_epochs_before_stopping = 1;
hyperparams.early_stopping_enabled = true;
@@ -212,13 +210,14 @@ async fn test_gradient_collapse_propagates_error() {
let mut hyperparams = DQNHyperparameters::conservative();
ml::training_profile::DqnTrainingProfile::load("dqn-smoketest").apply_to(&mut hyperparams);
// Force gradient collapse detection: threshold = lr × multiplier = 5e-9 × 1e9 = 5.0
// Typical grad norms are ~0.5-2.0, so threshold 5.0 is always above → collapse triggers.
// Force gradient collapse detection: threshold = lr × multiplier = 5e-9 × 1e12 = 5000.0
// With v_range ±240 (C51), grad norms can reach 100-10000. Threshold must be above
// the maximum expected norm to guarantee collapse detection fires.
// GPU PER requires buffer_size >= 1024. Warmup = 1024 × 0.2 = 204 steps.
// max_training_steps_per_epoch=300 clears warmup in epoch 1 (300 > 204).
hyperparams.learning_rate = 5e-9;
hyperparams.epochs = 10;
hyperparams.gradient_collapse_multiplier = 1e9;
hyperparams.gradient_collapse_multiplier = 1e12;
hyperparams.gradient_collapse_patience = 3;
hyperparams.min_epochs_before_stopping = 1;
hyperparams.early_stopping_enabled = true;

View File

@@ -355,6 +355,10 @@ async fn test_dqn_training_smoke() -> Result<()> {
dqn_config.use_iqn = false;
dqn_config.epsilon_start = 0.3;
dqn_config.epsilon_end = 0.01;
// Walk-forward uses raw price returns (~0.001), NOT the production reward
// function (scale 10.0). Override v_range to match this simpler reward scale.
dqn_config.v_min = -10.0;
dqn_config.v_max = 10.0;
let mut strategy = DqnStrategy::new(dqn_config)?;
let report = harness.validate(&mut strategy, &ts_data)?;