- Docker: Delete 23 deprecated Dockerfiles, fix CI/CD to use Dockerfile.foxhunt-build - Config: Remove 36 .env files, keep 4 essential, delete config/environments/ - Docs: Archive 614 Wave D files to docs/archive/wave_d/, 95% reduction in root - Scripts: Delete 56 deprecated scripts, keep 58 production-critical (49% reduction) - Python: Organize 37 scripts into scripts/python/ subdirectories, delete ml/python/ - Build: Remove 1GB artifacts, delete old venvs, clean Python cache from git - Migrations: Delete deprecated directory (4,432 lines), remove duplicate database/migrations/ - Infrastructure: Delete deployment/ (61 files), docs/scripts/ (8 files) Total impact: ~2,500 files cleaned, 750MB+ space freed, zero production impact All deleted scripts backed up to archives. runpod/ and tests/runpod/ preserved. data_acquisition_service retained per user request.
5.0 KiB
Agent 3: Final Integration Test Report
Date: 2025-10-26 Task: Commit all fixes from Agents 1 & 2, run final integration test Status: ❌ FAILED - OOM During Validation
Commits Created
Commit 1: 56956818
fix(ml): Final TFT memory leak fixes - validation cache + CLI defaults
Issue: This commit INCORRECTLY claimed to include Agent 1's cache clearing fix, but the actual code only called sync_cuda_device() which doesn't clear the model's attention cache.
Commit 2: 85e51f6e (CRITICAL FIX)
fix(ml): CRITICAL - Add model.clear_cache() to validation loop
Fix: Added self.model.clear_cache() inside the validation loop every 10 batches. This is the actual fix needed to prevent cache accumulation.
Integration Test Results
Command
cargo run -p ml --example train_tft_parquet --release --features cuda -- \
--parquet-file test_data/ES_FUT_small.parquet \
--batch-size 1 \
--epochs 5 \
--use-gpu
Results
BUILD: ✅ SUCCESS (1m 33s compile) COMMIT: 85e51f6e TRAINING: 0/5 epochs completed VALIDATION: ❌ OOM (died at validation start) MEMORY: Peak usage 1611MB before validation → OOM during validation VERDICT: ❌ VALIDATION OOM - FIXES INSUFFICIENT
Memory Profile Analysis
[MEMORY] Epoch 0 START: 1291.0MB / 4096.0MB (31.5%)
[Training Phase]
[MEMORY] Epoch 0 AFTER_TRAINING: 1611.0MB / 4096.0MB (39.3%)
[MEMORY] Dropped optimizer before validation to free ~1100MB AdamW state
[MEMORY] Epoch 0 BEFORE_VALIDATION: 1611.0MB / 4096.0MB (39.3%)
[MEMORY] Validation START (Epoch 0): 1611.0MB / 4096.0MB
Error: Training OOM after 0 retries (final batch_size=1)
Problem: Starting validation at 1611MB + 176 validation batches (each adds ~14MB) = ~4000MB total, exceeding 4096MB GPU memory.
Root Cause Analysis
Issue #1: Optimizer Not Actually Dropped
The log says "Dropped optimizer before validation to free ~1100MB AdamW state" but memory stays at 1611MB (39.3%). This means:
- The optimizer drop is not actually freeing memory
- OR the memory is immediately reallocated by CUDA
- OR there's another memory leak preventing the reclaim
Issue #2: Validation Cache Accumulation
Even with model.clear_cache() every 10 batches:
- 176 validation batches / 10 = 17 cache clears
- Between clears: 10 batches × ~14MB = 140MB accumulation
- Total leak over validation: 17 × 140MB = 2380MB
This exceeds available memory (4096MB - 1611MB = 2485MB).
Issue #3: Batch Size = 1 Inefficiency
With batch_size=1, we have 176 separate forward passes instead of batching. Each creates tensors, runs attention, etc., fragmenting GPU memory.
Proposed Solutions
Option A: Aggressive Cache Clearing (QUICK FIX)
Change: Clear cache EVERY batch instead of every 10 batches
Impact: Validation slower (~10% overhead) but memory usage <100MB
Effort: 2 minutes (change i % 10 to i % 1)
Option B: Force CUDA Synchronization (RECOMMENDED)
Change: Add explicit CUDA memory clearing:
if i % 10 == 0 && self.device.is_cuda() {
self.model.clear_cache();
// Force CUDA to actually free memory
if let Ok(mut sizer) = AutoBatchSizer::new() {
sizer.force_memory_cleanup()?;
}
}
Impact: Ensures memory is actually freed, not just marked for GC
Effort: 15 minutes (implement force_memory_cleanup())
Option C: Increase Validation Batch Size
Change: Use validation_batch_size=4 instead of 1
Impact: 176 batches → 44 batches (4× reduction in memory churn)
Effort: 1 minute (command line flag)
Risk: May still OOM if optimizer isn't actually freed
Option D: Skip Validation on Small Datasets (WORKAROUND)
Change: Don't run validation when dataset <1000 samples Impact: Training completes but no validation metrics Effort: 5 minutes Drawback: Doesn't fix the underlying memory leak
Recommendation
Immediate: Try Option A (clear cache every batch) + Option C (batch_size=4) Next: Implement Option B (force CUDA cleanup) if Option A fails Long-term: Profile optimizer drop to confirm it's actually freeing 1100MB
Test Command for Next Iteration
# Option A + C combined
cargo run -p ml --example train_tft_parquet --release --features cuda -- \
--parquet-file test_data/ES_FUT_small.parquet \
--batch-size 4 \
--validation-batch-size 4 \
--epochs 5 \
--use-gpu
# Expected: 704/4=176 train batches, 176/4=44 val batches (75% reduction)
Files Modified
-
ml/src/trainers/tft.rs
- Line 1500: Added
self.model.clear_cache()every 10 batches - Still OOMs due to optimizer not freeing memory
- Line 1500: Added
-
ml/examples/train_tft_parquet.rs (Agent 2, not committed)
- CLI defaults fix not yet in codebase
- Needs separate commit
Conclusion
Status: ❌ Fixes applied but insufficient Blocker: Optimizer drop not freeing 1100MB as expected Next Steps: Implement aggressive cache clearing (every batch) + larger validation batch size ETA: 15-30 minutes for Option A+C, 1 hour for Option B if needed