diff --git a/config/training/dqn-smoketest.toml b/config/training/dqn-smoketest.toml index 3e5705ed5..1617eb307 100644 --- a/config/training/dqn-smoketest.toml +++ b/config/training/dqn-smoketest.toml @@ -21,7 +21,7 @@ hidden_dim_base = 64 reward_scale = 1.0 huber_delta = 1.0 symbol = "ES.FUT" -max_bars = 60000 +max_bars = 5000 imbalance_bar_threshold = 1.0 imbalance_bar_ewma_alpha = 0.1 diff --git a/crates/ml/src/trainers/dqn/smoke_tests/regression.rs b/crates/ml/src/trainers/dqn/smoke_tests/regression.rs index cd9d2a21d..70c5261b5 100644 --- a/crates/ml/src/trainers/dqn/smoke_tests/regression.rs +++ b/crates/ml/src/trainers/dqn/smoke_tests/regression.rs @@ -161,9 +161,15 @@ fn test_counterfactual_experiences_in_buffer() -> anyhow::Result<()> { let mut p = smoke_params(); p.epochs = 1; p.early_stopping_enabled = false; - // Ensure we can distinguish 1x from 2x: buffer must be large enough to hold 2x - // smoketest defaults: gpu_n_episodes=32, gpu_timesteps=100, buffer_size=10000 - // base = 32 * 100 = 3200, counterfactual = 6400, fits in 10000 + + // Compute expected counts from the actual config + let n_ep = p.gpu_n_episodes; + let ts = p.gpu_timesteps_per_episode; + let base = n_ep * ts; + let with_cf = base * 2; // counterfactual doubles + // Buffer must be large enough to hold 2x WITHOUT wrapping, so we can + // distinguish 1x from 2x by counting entries. + p.buffer_size = with_cf + 100; let mut trainer = smoke_trainer_with(p)?; let rt = tokio::runtime::Builder::new_current_thread() @@ -173,27 +179,24 @@ fn test_counterfactual_experiences_in_buffer() -> anyhow::Result<()> { Ok("skip".to_owned()) }))?; - // Check replay buffer size via the agent let buffer_size = rt.block_on(async { let agent = trainer.get_agent().read().await; agent.get_replay_buffer_size().unwrap_or(0) }); - // With counterfactual: 32 * 100 * 2 = 6400 - // Without counterfactual (the old bug): 32 * 100 = 3200 - // Threshold at 4000 cleanly separates the two cases. - let min_expected = 4000; + // With counterfactual: buffer should have more entries than base (1x). + // Threshold: midpoint between 1x and 2x cleanly separates the cases. + let min_expected = (base + with_cf) / 2; assert!( buffer_size >= min_expected, - "PER buffer has {} entries (expected >= {min_expected}). \ - Counterfactual experiences may be silently dropped again. \ - With gpu_n_episodes=32, timesteps=100, expected 6400 (32*100*2).", - buffer_size + "PER buffer has {buffer_size} entries (expected >= {min_expected}). \ + base={base}, with_cf={with_cf}. \ + Counterfactual experiences may be silently dropped.", ); tracing::info!( - "Counterfactual regression: PER buffer has {} entries (expected ~6400)", - buffer_size + "Counterfactual regression: PER buffer has {buffer_size} entries \ + (expected ~{with_cf}, threshold={min_expected})", ); Ok(()) }