Changes: - CLAUDE.md: Update OOM fix validation status - Add comprehensive documentation (30+ markdown reports) - LSTM encoder varmap bug fix (tft/lstm_encoder.rs:290) - Quantized LSTM layer matching fix (tft/quantized_lstm.rs) - Hyperopt paths module (ml/src/hyperopt/paths.rs) - Training path tests for all adapters (DQN, MAMBA-2, PPO, TFT) - Checkpoint integrity tests - Script cleanup: Remove 29 obsolete deployment scripts - Archive old scripts to scripts/archive/ - New deployment utilities: check_gpu_availability.py, monitor_hyperopt.sh Validation: - OOM fixes validated: 5/5 trials successful (pod b6kc3mc5lbjiro) - Batch-size-max 256 tested successfully - All hyperopt adapters working correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9.4 KiB
Hyperopt Log File Implementation - COMPLETE
Status: ✅ IMPLEMENTED
All four ML model adapters now write proper log files during hyperparameter optimization training.
Implementation Summary
Files Modified
-
ml/src/hyperopt/adapters/mamba2.rs
- Added imports:
std::fs::OpenOptions,std::io::Write as IoWrite - Added helper functions:
write_training_log_mamba2(),write_trial_result_mamba2() - Modified
train_with_params(): trial timing, log writes at start/end - Lines modified: 37-38 (imports), 703-742 (helpers), 750, 783-786, 942-959 (logging)
- Added imports:
-
ml/src/hyperopt/adapters/dqn.rs
- Added imports:
std::fs::OpenOptions,std::io::Write as IoWrite - Added helper functions:
write_training_log_dqn(),write_trial_result_dqn() - Modified
train_with_params(): trial timing, log writes, directory logging - Lines modified: 35-37 (imports), 289-328 (helpers), 336, 348-352, 363-364, 474-491 (logging)
- Added imports:
-
ml/src/hyperopt/adapters/ppo.rs
- Added imports:
std::fs::OpenOptions,std::io::Write as IoWrite - Added helper functions:
write_training_log_ppo(),write_trial_result_ppo() - Modified
train_with_params(): trial timing, log writes, directory creation - Lines modified: 35-37 (imports), 248-287 (helpers), 295, 304-316, 446-463 (logging)
- Added imports:
-
ml/src/hyperopt/adapters/tft.rs
- Added imports:
std::fs::OpenOptions,std::io::Write as IoWrite - Added helper functions:
write_training_log_tft(),write_trial_result_tft() - Modified
train_with_params(): trial timing, log writes, directory creation - Lines modified: 37-39 (imports), 279-318 (helpers), 326, 335-339, 356-363, 435-452 (logging)
- Added imports:
Features Implemented
1. Training Log File ({logs_dir}/training.log)
Format:
[2025-10-29 14:32:15] === Starting MAMBA-2 Trial ===
Params: Mamba2Params {
learning_rate: 0.0001,
batch_size: 32,
dropout: 0.1,
...
}
[2025-10-29 14:34:23] Training completed in 128.45s: val_loss=0.234567, train_loss=0.198765, accuracy=67.89%
Features:
- UTC timestamps for consistency across deployments
- Append mode (accumulates across trials)
- Params logged at trial start (full Debug format)
- Metrics logged at trial end (key metrics + duration)
- Model-specific metric formatting:
- MAMBA-2:
val_loss, train_loss, accuracy - DQN:
loss, q_value - PPO:
val_policy_loss, val_value_loss - TFT:
val_loss, train_loss, rmse
- MAMBA-2:
2. Trial Results JSON ({hyperopt_dir}/trials.json)
Format:
[
{
"trial_num": 0,
"params": {
"learning_rate": 0.0001,
"batch_size": 32,
"dropout": 0.1,
...
},
"objective": 0.234567,
"duration_secs": 128.45
},
{
"trial_num": 0,
"params": { ... },
"objective": 0.198765,
"duration_secs": 115.23
}
]
Features:
- JSON array format (pretty-printed)
- Accumulates trials across multiple runs
- Compatible with
TrialResult<P>generic type - Trial numbers set to 0 (optimizer overwrites with actual trial number)
- Includes full parameter set for reproducibility
- Objective value (lower is better)
- Duration in seconds
3. Directory Structure
/runpod-volume/training_runs/{model_name}/run_{run_id}/
├── checkpoints/
│ └── best_model.safetensors
├── logs/
│ └── training.log # ← NEW: Training progress log
├── hyperopt/
│ └── trials.json # ← NEW: Trial results JSON
└── metrics/
Implementation Pattern
Helper Functions
Each adapter has two helper functions with model-specific names to avoid conflicts:
-
write_training_log_{model}(logs_dir, message)- Creates/appends to
training.log - Adds UTC timestamp prefix
- Non-fatal errors (
.ok()to ignore I/O failures)
- Creates/appends to
-
write_trial_result_{model}(hyperopt_dir, trial_result)- Creates/updates
trials.json - Reads existing trials, appends new one
- Pretty-prints JSON for human readability
- Non-fatal errors (
.ok()to ignore I/O failures)
- Creates/updates
Integration Points in train_with_params()
fn train_with_params(&mut self, params: Self::Params) -> Result<Self::Metrics, MLError> {
// 1. START: Trial timing
let trial_start = std::time::Instant::now();
// 2. Log trial start (after parameter logging)
write_training_log_{model}(
&self.training_paths.logs_dir(),
&format!("=== Starting {MODEL} Trial ===\nParams: {:#?}", params)
).ok();
// 3. Create all directories (checkpoints, logs, hyperopt, metrics)
self.training_paths.create_all()
.map_err(|e| MLError::ModelError(...))?;
// ... existing training code ...
// 4. END: Log completion + write trial result
let duration_secs = trial_start.elapsed().as_secs_f64();
write_training_log_{model}(
&self.training_paths.logs_dir(),
&format!("Training completed in {:.2}s: metrics={:#?}", duration_secs, metrics)
).ok();
let trial_result = crate::hyperopt::traits::TrialResult {
trial_num: 0, // Overwritten by optimizer
params,
objective: Self::extract_objective(&metrics),
duration_secs,
};
write_trial_result_{model}(&self.training_paths.hyperopt_dir(), &trial_result).ok();
Ok(metrics)
}
Error Handling
-
Non-fatal I/O errors:
.ok()used on all log writes- Training continues even if log write fails
- Prevents trial failure due to disk issues
- Console logging (via
info!()) remains as backup
-
Directory creation: Fails fast with proper error
- Critical path (needed for checkpoints)
- MLError::ModelError with context
Verification
Quick Test
# Run hyperopt examples (any model)
cargo run -p ml --example hyperopt_mamba2_demo --release --features cuda
# Check logs were created
ls -lh /tmp/ml_training/training_runs/mamba2/run_*/logs/training.log
cat /tmp/ml_training/training_runs/mamba2/run_*/hyperopt/trials.json
Expected Output Structure
training.log:
- Multiple timestamped entries per trial
- Start marker with full params (Debug format)
- End marker with key metrics + duration
- Chronological order (append mode)
trials.json:
- Valid JSON array
- One object per trial
- All fields present (trial_num, params, objective, duration_secs)
- Pretty-printed (2-space indentation)
Dependencies
No new dependencies added. Uses existing:
std::fs::OpenOptions- file I/Ostd::io::Write- write operationschrono::Utc- timestamps (already in ml/Cargo.toml)serde_json- JSON serialization (already in ml/Cargo.toml)
Production Deployment
Runpod Volume Mount
Logs will be written to:
/runpod-volume/training_runs/{model}/run_{run_id}/
├── logs/training.log
└── hyperopt/trials.json
S3 Sync
These files will be automatically synced to S3 via existing upload logic:
aws s3 sync /runpod-volume/training_runs/ s3://se3zdnb5o4/training_runs/ \
--endpoint-url https://s3api-eur-is-1.runpod.io \
--profile runpod
Monitoring
Check hyperopt progress:
# View recent logs
tail -f /runpod-volume/training_runs/mamba2/run_*/logs/training.log
# Check trial count
jq 'length' /runpod-volume/training_runs/mamba2/run_*/hyperopt/trials.json
# View best trial
jq '[.[] | {trial: .trial_num, obj: .objective, dur: .duration_secs}] | sort_by(.obj) | .[0]' \
/runpod-volume/training_runs/mamba2/run_*/hyperopt/trials.json
Testing Checklist
- MAMBA-2 adapter: Log functions added
- DQN adapter: Log functions added
- PPO adapter: Log functions added
- TFT adapter: Log functions added
- All adapters: Imports added
- All adapters: Trial timing added
- All adapters: Directory creation verified
- All adapters: Start/end logging added
- All adapters: Trial result JSON write added
- Compilation check (blocked by sqlx database connection)
- Integration test (run hyperopt examples)
- Runpod deployment test
Notes
- Trial Numbers: Set to 0 in adapters, optimizer overwrites with actual trial number
- Timestamp Format: UTC ISO 8601 (
%Y-%m-%d %H:%M:%S) - Append vs Overwrite: Logs append, JSON array accumulates
- Metrics Logging: Model-specific format (different metrics per model type)
- Directory Creation: Uses
TrainingPaths.create_all()pattern from checkpoints
Related Files
- Implementation guide:
/home/jgrusewski/Work/foxhunt/HYPEROPT_LOG_IMPLEMENTATION.md - TrainingPaths:
/home/jgrusewski/Work/foxhunt/ml/src/hyperopt/paths.rs - TrialResult:
/home/jgrusewski/Work/foxhunt/ml/src/hyperopt/traits.rs:364-373 - Examples:
/home/jgrusewski/Work/foxhunt/ml/examples/hyperopt_mamba2_demo.rs/home/jgrusewski/Work/foxhunt/ml/examples/hyperopt_dqn_demo.rs/home/jgrusewski/Work/foxhunt/ml/examples/hyperopt_ppo_demo.rs/home/jgrusewski/Work/foxhunt/ml/examples/hyperopt_tft_demo.rs
Next Steps
-
Fix SQLx Database Connection (blocking compilation)
- Start PostgreSQL:
docker-compose up -d postgres - Or disable regime module temporarily
- Start PostgreSQL:
-
Integration Testing
- Run hyperopt examples with 2-3 trials
- Verify log files created
- Verify JSON format correct
- Check S3 sync works
-
Runpod Deployment
- Deploy with new code
- Monitor log file creation
- Verify S3 upload includes logs
- Check trial progress via JSON
-
Documentation Update
- Update CLAUDE.md with log file locations
- Add monitoring commands to deployment guide
- Document log format in ML_TRAINING_PARQUET_GUIDE.md