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>
This commit is contained in:
jgrusewski
2025-11-27 23:46:13 +01:00
parent 2c1acda2f3
commit 2df1ea92e1
763 changed files with 247870 additions and 1714 deletions

View File

@@ -0,0 +1,199 @@
═══════════════════════════════════════════════════════════════════════════════
AGENT 19: DQN HYPEROPT ANTI-OVERFITTING REVIEW - QUICK SUMMARY
═══════════════════════════════════════════════════════════════════════════════
📊 CURRENT STATE
───────────────────────────────────────────────────────────────────────────────
✅ Search Space: 22D (WAVE 19)
✅ Well-tuned ranges: LR, gamma, buffer_size, entropy
✅ Buffer size increased: [50K→100K] → [100K→500K] (WAVE 24 anti-overfitting)
✅ Network architecture: [256, 128, 64] (3 layers, 112K params)
🚨 CRITICAL GAPS
───────────────────────────────────────────────────────────────────────────────
❌ Dropout: Implemented in QNetworkConfig but NOT in hyperopt search space
❌ Weight Decay: Missing from DQN optimizer (exists in MAMBA-2)
⚠️ LayerNorm: Enabled by default, not tunable (low priority)
📋 PROPOSED UPDATES
───────────────────────────────────────────────────────────────────────────────
┌─────────────────────────────────────────────────────────────────────────────┐
│ TIER 1: CRITICAL ANTI-OVERFITTING (Immediate) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ P0 🔥 ADD DROPOUT TO SEARCH SPACE │
│ ───────────────────────────────────────────────────────────────────────────│
│ Parameter: dropout_prob: f64 │
│ Range: [0.1, 0.5] (linear) │
│ Default: 0.2 (20% dropout) │
│ Effort: LOW (QNetworkConfig.dropout_prob exists) │
│ Impact: HIGH (+10-15% out-of-sample Sharpe) │
│ Search: 23D (22D → 23D) │
│ │
│ CODE CHANGE: │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ pub struct DQNParams { │ │
│ │ // ... existing 22 params ... │ │
│ │ pub dropout_prob: f64, // NEW: [0.1, 0.5] │ │
│ │ } │ │
│ │ │ │
│ │ impl ParameterSpace for DQNParams { │ │
│ │ fn continuous_bounds() -> Vec<(f64, f64)> { │ │
│ │ vec![ │ │
│ │ // ... existing 22 bounds ... │ │
│ │ (0.1, 0.5), // 22: dropout_prob │ │
│ │ ] │ │
│ │ } │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ P1 🔧 ADD WEIGHT DECAY (AdamW Optimizer) │
│ ───────────────────────────────────────────────────────────────────────────│
│ Parameter: weight_decay: f64 │
│ Range: [1e-5, 1e-3] (log scale) │
│ Default: 1e-4 (moderate L2 penalty) │
│ Effort: MEDIUM (upgrade Adam → AdamW) │
│ Impact: MEDIUM (+5-10% generalization) │
│ Search: 24D (23D → 24D) │
│ │
│ CODE CHANGE: │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ pub struct DQNParams { │ │
│ │ // ... existing params + dropout ... │ │
│ │ pub weight_decay: f64, // NEW: [1e-5, 1e-3] log │ │
│ │ } │ │
│ │ │ │
│ │ // Optimizer upgrade (ml/src/dqn/network.rs): │ │
│ │ use candle_optimisers::AdamW; // BEFORE: Adam │ │
│ │ let optimizer = AdamW::new( │ │
│ │ vars.all_vars(), │ │
│ │ learning_rate, │ │
│ │ weight_decay // NEW PARAMETER │ │
│ │ )?; │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ TIER 2: OPTIONAL REFINEMENTS (Consider if overfitting persists) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ P2 ⚙️ LAYER NORMALIZATION TOGGLE (Low Priority) │
│ ───────────────────────────────────────────────────────────────────────────│
│ Parameter: use_layer_norm: bool │
│ Current: Fixed TRUE (default enabled) │
│ Effort: LOW (QNetworkConfig.use_layer_norm exists) │
│ Impact: LOW (likely neutral, stability > regularization) │
│ Verdict: SKIP unless experiments show disabling helps │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
📈 EXPECTED IMPROVEMENTS
───────────────────────────────────────────────────────────────────────────────
Dropout (P0): +10-15% out-of-sample Sharpe (+0.05 to +0.15)
Weight Decay (P1): +5-10% generalization gap reduction
Combined (P0 + P1): +15-25% total improvement
Trial variance: -20-30% (more consistent hyperopt results)
🔍 CURRENT PARAMETER ANALYSIS
───────────────────────────────────────────────────────────────────────────────
✅ WELL-TUNED (No changes needed):
├─ learning_rate: [2e-5, 8e-5] (log) ← Narrowed from [1e-5, 3e-4]
├─ gamma: [0.95, 0.99] (linear) ← Optimal for HFT
├─ buffer_size: [100K, 500K] (log) ← WAVE 24: +5x diversity
└─ entropy_coeff: [0.0, 0.1] (linear) ← Prevents policy collapse
⚠️ ACCEPTABLE (With mitigations):
├─ batch_size: [64, 160] (linear) ← Wave 6 enforces ≥120 for LR>2e-4
└─ huber_delta: [10, 40] (log) ← Upper bound could amplify outliers
❌ MISSING REGULARIZATION:
├─ dropout_prob: NOT IN SEARCH SPACE ← Implemented but not tunable
├─ weight_decay: NOT IN OPTIMIZER ← Exists in MAMBA-2
└─ use_layer_norm: NOT TUNABLE ← Fixed TRUE (low priority)
📊 OVERFITTING RISK FACTORS
───────────────────────────────────────────────────────────────────────────────
Network Params: 112,320 (3 layers: [256, 128, 64])
Training Experiences: ~300,000 (replay buffer)
Param/Data Ratio: 0.37 (HIGH OVERFITTING RISK ⚠️ )
Solution: Dropout 0.2-0.4 + Weight Decay 1e-4 → Robust features
📁 FILES TO MODIFY
───────────────────────────────────────────────────────────────────────────────
PRIMARY:
/home/jgrusewski/Work/foxhunt/ml/src/hyperopt/adapters/dqn.rs
├─ Add dropout_prob, weight_decay to DQNParams struct (line 160)
├─ Update Default impl (line 260)
├─ Update continuous_bounds() → 23D/24D (line 309)
├─ Update from_continuous() (line 357)
├─ Update to_continuous() (line 458)
└─ Update param_names() (line 489)
SECONDARY:
/home/jgrusewski/Work/foxhunt/ml/src/trainers/dqn/config.rs
└─ Add dropout_prob, weight_decay to DQNHyperparameters
/home/jgrusewski/Work/foxhunt/ml/src/dqn/network.rs
└─ Upgrade Adam → AdamW optimizer (weight_decay support)
🧪 TESTING CHECKLIST
───────────────────────────────────────────────────────────────────────────────
□ cargo test --package ml --lib hyperopt::adapters::dqn::tests
□ cargo run --bin dqn_hyperopt -- --trials 3 --epochs 5 --dry-run
□ Verify 23D/24D search space compiles
□ Check AdamW optimizer availability in candle-optimisers
□ Run mini hyperopt (3 trials) to validate new params integrate correctly
🎯 IMPLEMENTATION PRIORITY
───────────────────────────────────────────────────────────────────────────────
PHASE 1 (P0): Dropout Integration [EFFORT: LOW | IMPACT: HIGH]
├─ 1. Add dropout_prob to DQNParams (→ 23D)
├─ 2. Update ParameterSpace impl (bounds, from/to, names)
├─ 3. Pass to QNetworkConfig in trainer
└─ 4. Test with 3-trial dry-run
PHASE 2 (P1): Weight Decay Integration [EFFORT: MED | IMPACT: MED]
├─ 1. Add weight_decay to DQNParams (→ 24D)
├─ 2. Upgrade Adam → AdamW optimizer
├─ 3. Verify candle-optimisers supports AdamW
└─ 4. Test gradient updates with weight decay
PHASE 3 (P2): Optional LayerNorm Toggle [EFFORT: LOW | IMPACT: LOW]
└─ Only implement if P0+P1 insufficient (unlikely)
📊 RATIONALE
───────────────────────────────────────────────────────────────────────────────
WHY DROPOUT IS CRITICAL:
├─ Network capacity: 112K params vs 300K experiences (0.37 ratio)
├─ Current dropout: Likely 0.0 (no regularization) or fixed 0.1
├─ Risk: Memorizing training distribution → poor generalization
└─ Fix: Dropout 0.2-0.4 forces robust feature learning
WHY WEIGHT DECAY HELPS:
├─ Current: Adam without L2 penalty → unbounded parameter growth
├─ Risk: Large weights → high noise sensitivity → overfitting
├─ Evidence: MAMBA-2 uses weight_decay=1e-3 for stability
└─ Fix: Weight decay → bounded parameters → smoother decisions
WHY LAYER NORMALIZATION IS LOWER PRIORITY:
├─ Current: Already enabled by default (use_layer_norm=true)
├─ Purpose: Gradient stability (not primarily anti-overfitting)
├─ Tradeoff: Adds parameters (2× per layer) → could increase overfitting
└─ Verdict: Keep enabled (stability > cost), don't tune unless needed
═══════════════════════════════════════════════════════════════════════════════
STATUS: ✅ REVIEW COMPLETE - READY FOR CODER AGENT IMPLEMENTATION
═══════════════════════════════════════════════════════════════════════════════
Next: Hand off to Coder Agent for Dropout (P0) and Weight Decay (P1) integration
Report: /home/jgrusewski/Work/foxhunt/docs/codebase-cleanup/agent19-dqn-hyperopt-anti-overfitting-review.md