Files
foxhunt/DQN_SHAPE_HUBER_TEST_REPORT.md
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

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_steps increments 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

  1. Shape Validation (Tests 1, 5)

    • Entropy penalty tensor shape
    • Indirect validation via training
  2. Loss Function (Tests 2, 3)

    • Huber loss integration (exposes bug)
    • MSE fallback (validates default path)
  3. End-to-End (Tests 4, 6, 8)

    • Combined entropy + training
    • Q-value stability
    • Batch training
  4. 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)

  1. Fix Huber loss dtype bug:

    • File: ml/src/dqn/dqn.rs
    • Line: 564
    • Change: let mask = abs_diff.le(delta)?.to_dtype(DType::F32)?;
  2. Re-run tests:

    cargo test -p ml --test dqn_shape_mismatch_and_huber_test
    
    • Expected: 8/8 passing

Future Enhancements

  1. Add performance benchmarks (Huber vs MSE)
  2. Test different huber_delta values (0.5, 1.0, 2.0)
  3. 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