Files
foxhunt/WAVE3_A5_HANDOFF.txt
jgrusewski 17d94e654c feat(dqn): Wave 10 - Architectural improvements and bug fixes
Wave 10 Summary:
- A1-A4: Architecture upgrades (4x network, LeakyReLU, Xavier init, diagnostics)
- A5-A6: Integration testing and production validation
- A7: Research hyperopt vs manual tuning (manual recommended)
- A8-A12: HOLD penalty tuning and critical bug fixes

Architecture Changes:
- Network expansion: [128,64,32] → [256,128,64] (2.5x parameters)
- LeakyReLU activation (alpha=0.01) to prevent dead neurons
- Xavier/Glorot initialization for better gradient flow
- Real-time diagnostic monitoring (Q-values, dead neurons, gradients)

Critical Bugs Fixed:
- Bug #1: HOLD penalty not wired to reward calculation
- Bug #2: Zero price error in calculate_hold_reward (velocity-based fix)
- Huber loss default enabled (Wave 9)
- Shape mismatch fix (Wave 8)

Test Results:
- Integration tests: 149/152 passing (98%)
- New tests: 40+ tests added across 15 files
- Xavier init: 5/5 tests passing
- HOLD penalty wiring: 4/4 tests passing
- Zero price fix: 4/4 tests passing

Known Issues:
- HOLD bias persists at ~100% despite penalties
- Gradient collapse: 217 instances per training run (norm=0.0)
- Reversed penalty effect: Higher penalties → worse Q-spread
- Root cause: Gradient clipping bottleneck (max_norm=10.0 vs penalty signal)

Phase 1 Trials (all completed without crashes):
- Penalty 0.5: Q-spread 250 pts, HOLD 100%
- Penalty 1.0: Q-spread 251 pts, HOLD 100%
- Penalty 2.0: Q-spread 255 pts, HOLD 100% (+ Q-value explosion)

Next Steps: Architectural investigation via parallel agent debugging

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 00:38:23 +01:00

178 lines
7.4 KiB
Plaintext

================================================================================
WAVE 3 - AGENT A5 HANDOFF: IMPLEMENT MULTI-OBJECTIVE FUNCTIONS
================================================================================
CURRENT STATUS:
✅ Agent A4 Complete: 15 unit tests created (579 lines)
⏳ Agent A5 Task: Implement 6 component functions
YOUR TASK:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Implement the 6 component functions for the multi-objective optimization
function. All tests are already written and will guide your implementation.
STEP 1: Extend DQNMetrics (1-2 hours)
───────────────────────────────────────────────────────────────────────────
File: ml/src/hyperopt/adapters/dqn.rs
Add these fields to DQNMetrics struct:
pub action_distribution: [f64; 3], // [BUY%, SELL%, HOLD%]
pub avg_gradient_norm: f64, // Average gradient norm
Update train_with_params() to populate these fields:
- Track actions via TrainingMonitor in ml/src/trainers/dqn.rs
- Track gradient norms during training
- Calculate percentages and averages
STEP 2: Implement Component Functions (2-3 hours)
───────────────────────────────────────────────────────────────────────────
File: ml/src/hyperopt/adapters/dqn.rs
Function 1: calculate_reward_component(metrics: &DQNMetrics) -> f64
Formula: -metrics.avg_episode_reward
Test: test_reward_component_normalization()
Function 2: calculate_diversity_penalty(metrics: &DQNMetrics) -> f64
Formula:
entropy = -Σ(p_i * ln(p_i)) for i in [BUY, SELL, HOLD]
max_entropy = ln(3) ≈ 1.099
diversity_score = entropy / max_entropy
penalty = 1.0 - diversity_score
Special case: ln(0) = 0 in entropy calculation
Tests:
- test_diversity_penalty_balanced_actions()
- test_diversity_penalty_extreme_hold()
- test_edge_case_zero_entropy()
Function 3: calculate_stability_penalty(metrics: &DQNMetrics) -> f64
Formula:
q_penalty = if Q < 0.5 { |0.5 - Q| }
else if Q > 10.0 { (Q - 10.0) * 0.1 }
else { 0.0 }
grad_penalty = if grad_norm > 10.0 { (grad_norm - 10.0) * 0.5 }
else { 0.0 }
stability_penalty = q_penalty + grad_penalty
Tests:
- test_stability_penalty_good_qvalues()
- test_stability_penalty_gradient_explosion()
- test_edge_case_q_value_boundaries()
- test_edge_case_gradient_norm_threshold()
Function 4: calculate_completion_penalty(metrics: &DQNMetrics, target: usize) -> f64
Formula: (target_epochs - epochs_completed) / target_epochs
Test: test_completion_penalty_early_stop()
Function 5: violates_hard_constraints(metrics: &DQNMetrics) -> bool
Constraints:
1. avg_q_value < -10.0 → true (Q-value floor)
2. train_loss > 1000.0 → true (loss ceiling)
3. epochs_completed < 20 → true (minimum epochs)
Otherwise → false
Tests:
- test_hard_constraint_q_value_floor()
- test_hard_constraint_training_loss_ceiling()
- test_hard_constraint_minimum_epochs()
Function 6: calculate_multiobjective(metrics: &DQNMetrics, target: usize) -> f64
Formula:
if violates_hard_constraints(metrics) {
return 1e6; // Penalty
}
let reward = calculate_reward_component(metrics);
let diversity = calculate_diversity_penalty(metrics);
let stability = calculate_stability_penalty(metrics);
let completion = calculate_completion_penalty(metrics, target);
0.8 * reward + 0.1 * diversity + 0.05 * stability + 0.05 * completion
Tests:
- test_multiobjective_optimal_trial()
- test_multiobjective_broken_trial()
- test_weight_sensitivity()
- All 3 hard constraint tests
STEP 3: Replace extract_objective() (1 hour)
───────────────────────────────────────────────────────────────────────────
File: ml/src/hyperopt/adapters/dqn.rs
Replace this code (lines 874-884):
fn extract_objective(metrics: &Self::Metrics) -> f64 {
-metrics.avg_episode_reward
}
With:
fn extract_objective(metrics: &Self::Metrics) -> f64 {
calculate_multiobjective(metrics, 50) // 50 = target epochs
}
STEP 4: Run Tests (5 minutes)
───────────────────────────────────────────────────────────────────────────
Verify all 15 tests pass:
cargo test -p ml --test dqn_hyperopt_multiobjective_test
Expected result:
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
REFERENCE FILES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Test File (defines all expected behavior):
ml/tests/dqn_hyperopt_multiobjective_test.rs
2. Design Document (explains why):
DQN_HYPEROPT_OBJECTIVE_ANALYSIS.md
3. Test Report (describes tests):
WAVE3_A4_MULTIOBJECTIVE_TESTS_REPORT.md
4. This Handoff:
WAVE3_A5_HANDOFF.txt
TIME BUDGET:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 1 (Extend DQNMetrics): 1-2 hours
Step 2 (Implement functions): 2-3 hours
Step 3 (Replace extract_objective): 1 hour
Step 4 (Run tests): 5 minutes
Total: 4-6 hours
SUCCESS CRITERIA:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ All 15 tests pass
✅ DQNMetrics extended with 2 new fields
✅ All 6 component functions implemented
✅ extract_objective() replaced with calculate_multiobjective()
✅ No compiler warnings (except test dead_code warning)
EXPECTED IMPACT:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
After your implementation, hyperopt will:
✅ Reject trials with Q-value collapse (< -10.0)
✅ Reject trials with numerical explosion (loss > 1000.0)
✅ Reject trials with early stopping (< 20 epochs)
✅ Penalize trials with degenerate actions (>95% single action)
✅ Reward trials with balanced actions (20-40% per action)
✅ Reward trials with healthy Q-values (-10.0 to 10.0)
This will prevent Trial #31-style failures where reward is high but training
is catastrophically unstable.
================================================================================
END OF WAVE 3 AGENT A5 HANDOFF
================================================================================