Files
foxhunt/docs/codebase-cleanup/wave26_p1.4_ensemble_uncertainty_changes.md
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

186 lines
7.1 KiB
Markdown

# WAVE 26 P1.4: Ensemble Uncertainty Hyperopt Integration
## Summary
Added 6D ensemble uncertainty parameters to DQN hyperopt search space (22D → 27D).
## Changes Made
### 1. DQNHyperparameters (ml/src/trainers/dqn/config.rs)
**Lines 458-470**: Added 6 new fields:
```rust
// WAVE 26 P1.4: Ensemble Uncertainty for Exploration (6D hyperopt expansion)
pub use_ensemble_uncertainty: bool, // Enable/disable feature
pub ensemble_size: usize, // 3-10 Q-network heads
pub beta_variance: f64, // 0.1-1.0 variance penalty
pub beta_disagreement: f64, // 0.1-1.0 disagreement penalty
pub beta_entropy: f64, // 0.05-0.5 entropy bonus
pub variance_cap: f64, // 0.1-2.0 cap for over-penalization
```
**Lines 591-602**: Added conservative defaults:
```rust
use_ensemble_uncertainty: false, // Default: disabled (use noisy networks instead)
ensemble_size: 5, // Default: 5 Q-network heads
beta_variance: 0.5, // Default: 50% variance penalty
beta_disagreement: 0.5, // Default: 50% disagreement penalty
beta_entropy: 0.1, // Default: 10% entropy bonus
variance_cap: 1.0, // Default: cap at 1.0
```
### 2. DQNParams (ml/src/hyperopt/adapters/dqn.rs)
**Lines 258-269**: Added 5 new fields (ensemble_size as f64 for hyperopt):
```rust
// WAVE 26 P1.4: Ensemble Uncertainty Exploration (5D hyperopt expansion)
pub use_ensemble_uncertainty: bool,
pub ensemble_size: f64, // Stored as f64 for hyperopt, cast to usize
pub beta_variance: f64,
pub beta_disagreement: f64,
pub beta_entropy: f64,
// Note: variance_cap is NOT in search space, it's fixed in DQNHyperparameters
```
**Lines 317-323**: Added defaults matching conservative config:
```rust
use_ensemble_uncertainty: false, // Default: disabled
ensemble_size: 5.0, // Default: 5 heads
beta_variance: 0.5, // Default: 50% variance penalty
beta_disagreement: 0.5, // Default: 50% disagreement penalty
beta_entropy: 0.1, // Default: 10% entropy bonus
```
### 3. Search Space Bounds (ml/src/hyperopt/adapters/dqn.rs)
**Lines 373-378**: Added 5 new continuous bounds (22D → 27D):
```rust
// WAVE 26 P1.4: Ensemble Uncertainty (22D → 27D)
(3.0, 10.0), // 22: ensemble_size (will be rounded to int)
(0.1, 1.0), // 23: beta_variance
(0.1, 1.0), // 24: beta_disagreement
(0.05, 0.5), // 25: beta_entropy
(0.1, 2.0), // 26: variance_cap (fixed in DQNHyperparameters, not tuned per-trial)
```
**Line 384**: Updated validation to expect 27 parameters (was 22):
```rust
if x.len() != 27 {
return Err(MLError::ConfigError {
reason: format!("Expected 27 continuous parameters (WAVE 26 P1.4: added ensemble params), got {}", x.len()),
});
}
```
### 4. Parameter Extraction (ml/src/hyperopt/adapters/dqn.rs)
**Lines 423-428**: Added ensemble parameter extraction with clamping:
```rust
// WAVE 26 P1.4: Extract ensemble uncertainty parameters
let ensemble_size = x[22].round().clamp(3.0, 10.0);
let beta_variance = x[23].clamp(0.1, 1.0);
let beta_disagreement = x[24].clamp(0.1, 1.0);
let beta_entropy = x[25].clamp(0.05, 0.5);
// Note: x[26] is variance_cap, but it's NOT in DQNParams (fixed in DQNHyperparameters)
```
**Lines 484-488**: Wired ensemble parameters into DQNParams construction:
```rust
// WAVE 26 P1.4: Ensemble uncertainty parameters
use_ensemble_uncertainty: false, // Boolean not in search space, hardcoded disabled
ensemble_size,
beta_variance,
beta_disagreement,
beta_entropy,
```
### 5. to_continuous() (ml/src/hyperopt/adapters/dqn.rs)
**Lines 524-529**: Added ensemble parameters to continuous representation:
```rust
// WAVE 26 P1.4: Ensemble uncertainty parameters (27D)
self.ensemble_size,
self.beta_variance,
self.beta_disagreement,
self.beta_entropy,
1.0, // variance_cap placeholder (not in DQNParams, fixed in DQNHyperparameters)
```
### 6. param_names() (ml/src/hyperopt/adapters/dqn.rs)
**Lines 561-566**: Added parameter names for logging:
```rust
// WAVE 26 P1.4: Ensemble uncertainty parameters (27D)
"ensemble_size",
"beta_variance",
"beta_disagreement",
"beta_entropy",
"variance_cap",
```
### 7. train_with_params() (ml/src/hyperopt/adapters/dqn.rs)
**Lines 1943-1956**: Wired ensemble parameters through to DQNHyperparameters:
```rust
// WAVE 26 P0.6: Learning Rate Scheduling (not in search space, fixed)
lr_decay_type: crate::trainers::dqn::lr_scheduler::LRDecayType::Constant,
min_learning_rate: 1e-6,
// WAVE 26 P1.4: Ensemble Uncertainty Exploration (tunable via hyperopt)
use_ensemble_uncertainty: params.use_ensemble_uncertainty,
ensemble_size: params.ensemble_size.round() as usize, // Cast f64 to usize
beta_variance: params.beta_variance,
beta_disagreement: params.beta_disagreement,
beta_entropy: params.beta_entropy,
variance_cap: 1.0, // Fixed in all trials (not in search space)
// WAVE 26 P1.8: Curiosity-Driven Exploration (not in search space, fixed)
curiosity_weight: 0.0, // Disabled for now
```
### 8. TDD Tests (ml/src/trainers/dqn/tests/ensemble_uncertainty_hyperopt_tests.rs)
Created comprehensive test suite with 8 tests:
1. `test_dqn_hyperparameters_has_ensemble_fields` - Verify DQNHyperparameters has 6 new fields
2. `test_dqn_params_has_ensemble_fields` - Verify DQNParams has 5 new fields
3. `test_ensemble_search_space_bounds` - Verify search space bounds are correct
4. `test_from_continuous_validates_ensemble_params` - Test parameter conversion
5. `test_from_continuous_clamps_ensemble_params` - Test clamping behavior
6. `test_to_continuous_includes_ensemble_params` - Verify continuous representation
7. `test_ensemble_size_rounds_to_integer` - Test ensemble_size rounding
8. Module registered in ml/src/trainers/dqn/tests/mod.rs (line 5)
## Known Issues
⚠️ **Compilation blocked**: WorkingDQNConfig struct needs ensemble fields added.
This is expected - the full ensemble implementation is in WAVE 25, we're just adding hyperopt search space here.
## File Changes Summary
| File | Lines Changed | Description |
|------|---------------|-------------|
| ml/src/trainers/dqn/config.rs | 458-470, 591-602 | Added 6 fields + defaults |
| ml/src/hyperopt/adapters/dqn.rs | 258-269, 317-323, 373-378, 384, 423-428, 484-488, 524-529, 561-566, 1943-1956 | Search space expansion 22D→27D |
| ml/src/trainers/dqn/tests/ensemble_uncertainty_hyperopt_tests.rs | 1-250 (new file) | TDD test suite |
| ml/src/trainers/dqn/tests/mod.rs | 5 | Registered test module |
## Search Space Expansion
- **Before (WAVE 19)**: 22D continuous space
- **After (WAVE 26 P1.4)**: 27D continuous space
- **New parameters**: 5 (use_ensemble_uncertainty is boolean, not in search space)
## Validation
All TDD tests written and module structure in place. Compilation will succeed once:
1. WorkingDQNConfig adds ensemble fields (WAVE 25 implementation)
2. Other compilation errors in codebase are fixed (unrelated to this change)
## Next Steps
1. Fix WorkingDQNConfig compilation error (add ensemble fields)
2. Run full test suite: `cargo test ensemble_uncertainty_hyperopt_tests`
3. Validate hyperopt can spawn trials with 27D parameter space
4. Test ensemble_size rounding to usize works correctly