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>
118 lines
4.0 KiB
Bash
Executable File
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
|