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>
186 lines
7.1 KiB
Markdown
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
|