DQN changes: improved attention, ensemble networks, hindsight replay, mixed precision, noisy layers, prioritized replay, RMSNorm, hyperopt adapter updates, and trainer enhancements with weight_decay support. Fix downstream crates broken by DQNConfig changes: - trading_service: import agent::DQNConfig directly, add weight_decay field - backtesting_service: update feature vector size 54 -> 51 - ml_training_service: convert compile-time sqlx macro to runtime query_as - pre-commit hook: add SQLX_OFFLINE=true for DB-free compilation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
106 lines
2.8 KiB
Rust
106 lines
2.8 KiB
Rust
//! Integration test for Noisy Networks in DQN
|
|
//!
|
|
//! Verifies that:
|
|
//! 1. NoisyLinear layers are correctly instantiated when use_noisy_nets=true
|
|
//! 2. reset_noise() is called before action selection
|
|
//! 3. Epsilon-greedy is disabled when using noisy nets
|
|
//! 4. Q-values change after reset_noise() (noise is working)
|
|
|
|
use ml::dqn::dqn::{DQNConfig, DQN};
|
|
|
|
#[test]
|
|
fn test_noisy_networks_enabled() -> Result<(), Box<dyn std::error::Error>> {
|
|
let config = DQNConfig {
|
|
state_dim: 54,
|
|
num_actions: 45,
|
|
hidden_dims: vec![128, 64],
|
|
use_noisy_nets: true,
|
|
noisy_sigma_init: 0.5,
|
|
warmup_steps: 0, // Disable warmup for testing
|
|
..Default::default()
|
|
};
|
|
|
|
let mut dqn = DQN::new(config)?;
|
|
|
|
// Verify noisy nets are enabled
|
|
assert!(dqn.is_using_noisy_nets());
|
|
|
|
// Create dummy state
|
|
let state = vec![0.0_f32; 54];
|
|
|
|
// Select action - this should call reset_noise() internally
|
|
let action1 = dqn.select_action(&state)?;
|
|
let action2 = dqn.select_action(&state)?;
|
|
|
|
// Actions may differ due to noise (not guaranteed, but highly likely)
|
|
// The important thing is that this doesn't panic
|
|
println!("Action 1: {:?}, Action 2: {:?}", action1, action2);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_noisy_networks_disabled() -> Result<(), Box<dyn std::error::Error>> {
|
|
let config = DQNConfig {
|
|
state_dim: 54,
|
|
num_actions: 45,
|
|
hidden_dims: vec![128, 64],
|
|
use_noisy_nets: false, // Disabled
|
|
warmup_steps: 0,
|
|
..Default::default()
|
|
};
|
|
|
|
let mut dqn = DQN::new(config)?;
|
|
|
|
// Verify noisy nets are disabled
|
|
assert!(!dqn.is_using_noisy_nets());
|
|
|
|
// Create dummy state
|
|
let state = vec![0.0_f32; 54];
|
|
|
|
// Select action - should use standard epsilon-greedy
|
|
let _action = dqn.select_action(&state)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_noisy_networks_epsilon_override() -> Result<(), Box<dyn std::error::Error>> {
|
|
let config = DQNConfig {
|
|
state_dim: 54,
|
|
num_actions: 45,
|
|
hidden_dims: vec![128, 64],
|
|
use_noisy_nets: true,
|
|
epsilon_start: 1.0, // Should be ignored when noisy nets enabled
|
|
epsilon_end: 0.01,
|
|
warmup_steps: 0,
|
|
..Default::default()
|
|
};
|
|
|
|
let mut dqn = DQN::new(config)?;
|
|
|
|
// Create dummy state
|
|
let state = vec![0.0_f32; 54];
|
|
|
|
// Select multiple actions
|
|
// With epsilon=0 (effective), we should get greedy actions (with learned noise)
|
|
for _ in 0..10 {
|
|
let _action = dqn.select_action(&state)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_noisy_networks_rainbow_default() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Rainbow DQN should have noisy nets enabled by default
|
|
let config = DQNConfig::rainbow();
|
|
|
|
let dqn = DQN::new(config)?;
|
|
|
|
// Verify Rainbow DQN has noisy nets
|
|
assert!(dqn.is_using_noisy_nets());
|
|
|
|
Ok(())
|
|
}
|