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>
5.1 KiB
Spectral Normalization Quick Reference - Agent 15
TL;DR - Decision Summary
FEASIBILITY: ✅ YES - Can be implemented COMPLEXITY: 🟡 Medium (custom power iteration, ~300 LOC) DEVELOPMENT TIME: ⏱️ 5-8 days PERFORMANCE COST: 📊 5-10% slower training RECOMMENDATION: ⚠️ Implement if overfitting is critical issue
Quick Facts
What is Spectral Normalization?
Constrains the Lipschitz constant of neural network layers by normalizing weights to have spectral norm ≤ 1. Prevents overfitting by limiting how much outputs can change for small input changes.
Candle Support
- ❌ NOT built-in to candle-nn
- ✅ CAN implement using power iteration
- ✅ Example code exists in codebase for power iteration
Implementation Approach
// Power iteration to find largest singular value
for _ in 0..n_iterations {
v = W^T * u / ||W^T * u||
u = W * v / ||W * v||
}
sigma = u^T * W * v
W_normalized = W / sigma
Should We Implement It?
✅ YES, if:
- Validation loss >> Training loss (severe overfitting)
- Current regularization (dropout=0.3, layer norm) insufficient
- Need state-of-the-art anti-overfitting technique
- Can afford 5-8 days development + 5-10% performance cost
❌ NO, if:
- Overfitting manageable with current techniques
- Development time/resources limited
- Performance overhead unacceptable
- Simple alternatives untried
🟡 ALTERNATIVES (easier/faster):
- Increase dropout (0.3 → 0.5) - 1 line change
- Add weight decay - already in optimizer
- Early stopping - simple to implement
- Reduce network size - config change
Implementation Plan (If Approved)
Phase 1: Core (2-3 days)
// File: ml/src/dqn/spectral_norm.rs
pub struct SpectralNorm {
u: Tensor, // [out_features]
v: Tensor, // [in_features]
n_power_iterations: usize,
}
impl SpectralNorm {
fn normalize_weights(&mut self, weight: &Tensor) -> Result<Tensor> {
// Power iteration algorithm
// Returns normalized weight
}
}
// Tests: correctness, convergence, performance
Phase 2: DQN Integration (1-2 days)
// File: ml/src/dqn/rainbow_network.rs
pub struct RainbowNetworkConfig {
pub use_spectral_norm: bool, // NEW
// ... existing fields
}
// Wrap NoisyLinear with SpectralNorm
Phase 3: Validation (2-3 days)
- Hyperopt with/without spectral norm
- Compare validation metrics
- Measure overfitting reduction
Key Metrics to Watch
Before Implementation
- Current validation loss vs training loss gap
- Overfitting severity on evaluation set
After Implementation
- Validation loss improvement (target: 10-20%)
- Training time overhead (expect: 5-10%)
- Gradient stability (should improve)
- Generalization to new market regimes
Technical Details
Memory Cost
Per layer: 2 * hidden_dim additional parameters (u, v vectors)
- Hidden dim 256: +512 params
- Hidden dim 512: +1024 params Total: Negligible (~0.1% increase)
Computation Cost
Per forward pass: 2-3 power iterations
- Each iteration: 2 matrix-vector multiplies + 2 normalizations
- Asymptotic: O(d²) where d = hidden_dim Overhead: ~5-10% training time increase
Convergence
- Typically converges in 1-3 power iterations
- Can start with n_iters=1, increase if unstable
- Track ||σ_new - σ_old|| to verify convergence
Integration Points
Current Architecture
// ml/src/dqn/rainbow_network.rs
- ✅ LayerNorm (lines 44, 59)
- ✅ Dropout (lines 40, 55)
- ✅ NoisyLinear (line 14)
- 🆕 SpectralNorm (proposed wrapper)
Recommended Wrapper
pub struct SpectralNoisyLinear {
noisy_linear: NoisyLinear,
spectral_norm: Option<SpectralNorm>, // Enable/disable
}
impl Module for SpectralNoisyLinear {
fn forward(&self, x: &Tensor) -> Result<Tensor> {
let weight = if let Some(sn) = &mut self.spectral_norm {
sn.normalize_weights(self.noisy_linear.weight())?
} else {
self.noisy_linear.weight().clone()
};
// Use normalized weight...
}
}
References
Papers
-
Miyato et al. (2018) - "Spectral Normalization for GANs"
- Original algorithm, power iteration method
-
Gouk et al. (2021) - "Regularization via Lipschitz Constants"
- Theoretical foundations
-
Yoshida & Miyato (2017) - "Spectral Norm for DRL"
- Application to reinforcement learning
Code Examples
- Power iteration:
ml/src/regime/transition_matrix.rs:273 - Eigenvalue estimation:
ml/src/checkpoint/enterprise_implementations.rs:308
Decision Checklist
Before implementing, confirm:
- Overfitting is measurably severe (validation >> training)
- Team approved 5-8 days development time
- Performance overhead (5-10%) acceptable
- Current regularization proven insufficient
- Alternative simple solutions tried
If all checked → IMPLEMENT If any unchecked → CONSIDER ALTERNATIVES
Full Research: See spectral_normalization_research.md
Agent: Research Agent 15
Status: ✅ Research Complete, Awaiting Decision