Files
foxhunt/scripts/test_dropout_scheduler.sh
jgrusewski 2df1ea92e1 feat(ml): WAVE 29 DQN Codebase Cleanup & Refactoring Campaign
BREAKING CHANGES:
- Removed orphaned dqn.rs monolithic trainer (4,975 lines)
- Removed orphaned dqn_ensemble.rs module (816 lines)
- Removed orphaned tft.rs and tft_complete_int8_integration_test.rs
- TFT trainer split into modular directory structure

DQN Module Refactoring:
- Split trainers/dqn.rs into modular structure (config.rs, statistics.rs, trainer.rs)
- Fixed hyperopt 39D search space (continuous params only)
- Boolean flags (use_dueling, use_double_dqn, use_per, use_noisy_nets) are now FIXED architectural decisions
- use_distributional defaults to false (Candle BUG #36 - scatter_add gradient issues)

Clean Module Structure:
- ml/src/trainers/dqn/ directory with proper mod.rs exports
- ml/src/trainers/tft/ directory with config.rs, types.rs, model.rs, trainer.rs, tests.rs
- All P0 features validated: TD-error clamping, batch diversity, LR scheduler, priority staleness

Documentation:
- Added comprehensive docs in docs/codebase-cleanup/
- ADR-001 for DQN refactoring decisions
- Rainbow DQN component matrix and quick reference guides

Build Status: Compiles with zero errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 23:46:13 +01:00

118 lines
4.0 KiB
Bash
Executable File

#!/bin/bash
# Standalone test for DropoutScheduler logic verification
cat > /tmp/test_dropout.rs << 'EOF'
/// Adaptive dropout scheduler that decreases dropout rate over training
#[derive(Debug, Clone)]
pub struct DropoutScheduler {
initial_rate: f64,
final_rate: f64,
decay_steps: usize,
current_step: usize,
}
impl DropoutScheduler {
pub fn new(initial_rate: f64, final_rate: f64, decay_steps: usize) -> Self {
Self {
initial_rate,
final_rate,
decay_steps,
current_step: 0,
}
}
pub fn get_rate(&self) -> f64 {
if self.decay_steps == 0 {
return self.final_rate;
}
let progress = (self.current_step as f64 / self.decay_steps as f64).min(1.0);
self.initial_rate * (1.0 - progress) + self.final_rate * progress
}
pub fn step(&mut self, steps: usize) {
self.current_step = self.current_step.saturating_add(steps);
}
pub fn current_step(&self) -> usize {
self.current_step
}
}
fn main() {
println!("Testing DropoutScheduler...\n");
// Test 1: Basic creation
let scheduler = DropoutScheduler::new(0.5, 0.1, 10000);
println!("✓ Test 1: Creation - initial rate: {}", scheduler.get_rate());
assert!((scheduler.get_rate() - 0.5).abs() < 1e-6);
// Test 2: Linear decay
let mut scheduler = DropoutScheduler::new(0.5, 0.1, 10000);
scheduler.step(2500); // 25%
let rate_25 = scheduler.get_rate();
println!("✓ Test 2: 25% progress - rate: {:.6} (expected: 0.4)", rate_25);
assert!((rate_25 - 0.4).abs() < 1e-6);
scheduler.step(2500); // 50%
let rate_50 = scheduler.get_rate();
println!("✓ Test 3: 50% progress - rate: {:.6} (expected: 0.3)", rate_50);
assert!((rate_50 - 0.3).abs() < 1e-6);
scheduler.step(2500); // 75%
let rate_75 = scheduler.get_rate();
println!("✓ Test 4: 75% progress - rate: {:.6} (expected: 0.2)", rate_75);
assert!((rate_75 - 0.2).abs() < 1e-6);
scheduler.step(2500); // 100%
println!("✓ Test 5: 100% progress - rate: {:.6} (expected: 0.1)", scheduler.get_rate());
assert!((scheduler.get_rate() - 0.1).abs() < 1e-6);
// Test 3: Beyond decay steps
scheduler.step(5000); // 150%
println!("✓ Test 6: Beyond decay - rate stays at: {:.6}", scheduler.get_rate());
assert!((scheduler.get_rate() - 0.1).abs() < 1e-6);
// Test 4: Step tracking
let mut scheduler = DropoutScheduler::new(0.8, 0.2, 1000);
assert_eq!(scheduler.current_step(), 0);
scheduler.step(100);
assert_eq!(scheduler.current_step(), 100);
println!("✓ Test 7: Step tracking works correctly");
// Test 5: Zero decay steps edge case
let scheduler = DropoutScheduler::new(0.5, 0.1, 0);
println!("✓ Test 8: Zero decay steps - immediately at final: {:.6}", scheduler.get_rate());
assert!((scheduler.get_rate() - 0.1).abs() < 1e-6);
// Test 6: Constant rate
let mut scheduler = DropoutScheduler::new(0.3, 0.3, 1000);
scheduler.step(500);
println!("✓ Test 9: Constant rate - stays at: {:.6}", scheduler.get_rate());
assert!((scheduler.get_rate() - 0.3).abs() < 1e-6);
// Test 7: Realistic schedule
let mut scheduler = DropoutScheduler::new(0.5, 0.05, 100_000);
scheduler.step(10_000); // Early training
let early = scheduler.get_rate();
println!("✓ Test 10: Realistic early training (10k/100k) - rate: {:.6}", early);
assert!(early > 0.4);
scheduler.step(40_000); // Mid training (total 50k)
let mid = scheduler.get_rate();
println!("✓ Test 11: Realistic mid training (50k/100k) - rate: {:.6}", mid);
assert!((mid - 0.275).abs() < 0.01);
scheduler.step(50_000); // Late training (total 100k)
let late = scheduler.get_rate();
println!("✓ Test 12: Realistic late training (100k/100k) - rate: {:.6}", late);
assert!((late - 0.05).abs() < 1e-6);
println!("\n✅ All tests passed!");
}
EOF
rustc /tmp/test_dropout.rs -o /tmp/test_dropout && /tmp/test_dropout