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>
6.5 KiB
DQN Shape Mismatch and Huber Loss Test Report
Created: 2025-11-05
Test File: /home/jgrusewski/Work/foxhunt/ml/tests/dqn_shape_mismatch_and_huber_test.rs
Purpose: Comprehensive validation of DQN entropy penalty and Huber loss functionality
Executive Summary
Created 8 comprehensive tests validating DQN entropy penalty calculation and Huber loss implementation. Test results: 7/8 passing (87.5%).
Key Finding: Discovered actual bug in Huber loss implementation (dtype mismatch at line 565 of ml/src/dqn/dqn.rs).
Test Coverage
| Test # | Test Name | Status | Purpose |
|---|---|---|---|
| 1 | test_entropy_penalty_shape_compatibility |
✅ PASS | Validates entropy penalty has correct scalar shape |
| 2 | test_huber_loss_integration |
❌ FAIL | EXPOSED BUG: dtype mismatch in Huber loss mask operation |
| 3 | test_mse_loss_fallback |
✅ PASS | Verifies MSE loss works when Huber disabled |
| 4 | test_training_with_entropy_penalty |
✅ PASS | End-to-end training with entropy penalty |
| 5 | test_entropy_penalty_indirect |
✅ PASS | Indirect validation of entropy calculation |
| 6 | test_q_value_stability_with_entropy |
✅ PASS | Q-values remain stable with entropy penalty |
| 7 | test_entropy_penalty_empty_actions |
✅ PASS | Empty action history handled gracefully |
| 8 | test_batch_training_with_entropy |
✅ PASS | Batch training with entropy penalty works |
Bug #2 (Huber Loss) - ACTUAL BUG FOUND
Error Details
dtype mismatch in sub, lhs: F32, rhs: U8
Location: ml/src/dqn/dqn.rs:565
Root Cause Analysis
File: ml/src/dqn/dqn.rs
Lines: 564-565
// Line 564: Creates U8 mask tensor (0 or 1)
let mask = abs_diff.le(delta)?; // Returns U8 dtype
// Line 565: Attempts to subtract U8 from F32 tensor
let one_minus_mask = (Tensor::ones(mask.shape(), DType::F32, device)? - &mask)?;
// ^^^^^^^^ ^^^^
// F32 tensor U8 tensor
// DTYPE MISMATCH!
Bug Impact
- Severity: CRITICAL
- Impact: Huber loss cannot be used (training fails immediately)
- Scope: All DQN training with
use_huber_loss=true - Workaround: Use MSE loss (
use_huber_loss=false)
Fix Required
Convert mask to F32 dtype before subtraction:
let mask = abs_diff.le(delta)?.to_dtype(DType::F32)?; // Convert U8 → F32
let one_minus_mask = (Tensor::ones(mask.shape(), DType::F32, device)? - &mask)?;
Bug #1 (Shape Mismatch) - ALREADY FIXED
Investigation Result
Status: ✅ NOT A BUG (already correct in codebase)
File: ml/src/dqn/dqn.rs
Line: 636
// Current implementation (CORRECT):
Tensor::from_vec(vec![penalty], &[], &self.device)
// ^^
// Scalar shape (correct)
Test Validation
Test test_entropy_penalty_shape_compatibility PASSES, confirming:
- Entropy penalty creates scalar tensor (shape
[]) - Tensor addition with loss tensor succeeds
training_stepsincrements correctly
Test File Structure
Utilities Module
mod test_utils {
fn create_minimal_config() -> WorkingDQNConfig
fn create_dummy_state(state_dim: usize) -> Vec<f32>
fn generate_experiences(dqn: &WorkingDQN, count: usize, state_dim: usize) -> Result<()>
fn populate_recent_actions(dqn: &mut WorkingDQN, actions: Vec<TradingAction>)
}
Test Categories
-
Shape Validation (Tests 1, 5)
- Entropy penalty tensor shape
- Indirect validation via training
-
Loss Function (Tests 2, 3)
- Huber loss integration (exposes bug)
- MSE fallback (validates default path)
-
End-to-End (Tests 4, 6, 8)
- Combined entropy + training
- Q-value stability
- Batch training
-
Edge Cases (Test 7)
- Empty action history
Test Execution Results
Compilation
cargo test -p ml --test dqn_shape_mismatch_and_huber_test
Status: ✅ COMPILES (with 4 unreachable_pub warnings)
Runtime Results
running 8 tests
test test_entropy_penalty_indirect ... ok
test test_entropy_penalty_shape_compatibility ... ok
test test_mse_loss_fallback ... ok
test test_entropy_penalty_empty_actions ... ok
test test_huber_loss_integration ... FAILED ← BUG EXPOSED
test test_training_with_entropy_penalty ... ok
test test_q_value_stability_with_entropy ... ok
test test_batch_training_with_entropy ... ok
test result: FAILED. 7 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
Time: 0.51s Pass Rate: 87.5% (7/8)
Key Achievements
1. Comprehensive Test Coverage
- 8 tests covering entropy penalty and Huber loss
- Edge cases (empty actions, batch training)
- MSE fallback validation
2. Bug Discovery
- CRITICAL BUG in Huber loss implementation exposed
- Exact location identified (line 565)
- Fix recommendation provided
3. Validation of Fixes
- Entropy penalty shape: ✅ CORRECT
- Huber loss config fields: ✅ ADDED
- MSE fallback: ✅ WORKING
4. Production-Ready Tests
- All tests will PASS after Huber loss bug fixed
- Can be used for regression testing
- Clear failure messages for debugging
Next Steps
Immediate (Wave 8-A3)
-
Fix Huber loss dtype bug:
- File:
ml/src/dqn/dqn.rs - Line: 564
- Change:
let mask = abs_diff.le(delta)?.to_dtype(DType::F32)?;
- File:
-
Re-run tests:
cargo test -p ml --test dqn_shape_mismatch_and_huber_test- Expected: 8/8 passing
Future Enhancements
- Add performance benchmarks (Huber vs MSE)
- Test different
huber_deltavalues (0.5, 1.0, 2.0) - Validate Q-value distributions with/without Huber loss
File Locations
- Test File:
/home/jgrusewski/Work/foxhunt/ml/tests/dqn_shape_mismatch_and_huber_test.rs - Source Bug:
/home/jgrusewski/Work/foxhunt/ml/src/dqn/dqn.rs(lines 564-565) - Report:
/home/jgrusewski/Work/foxhunt/DQN_SHAPE_HUBER_TEST_REPORT.md
Conclusion
Mission Accomplished: Created failing tests that expose real bug in Huber loss implementation.
- ✅ 8 comprehensive tests created
- ✅ BUG FOUND: dtype mismatch in Huber loss mask operation
- ✅ 7/8 tests passing (Huber loss test correctly fails)
- ✅ Clear fix path identified
- ✅ All tests will pass after fix applied
Impact: Prevents Huber loss from being deployed with critical bug. Fix is trivial (1-line change).
Generated: 2025-11-05 Agent: Wave 8-A2 (Test Creation) Status: ✅ COMPLETE