feat(training): cosine LR decay in TOML profile, min_epochs_before_stopping=80

- Added lr_decay_type (0=constant, 1=linear, 2=cosine) and lr_min to
  the TOML training profile system. Wired through apply_to() with
  total_steps derived from epochs.

- dqn-localdev.toml: lr_decay_type=2 (cosine 1e-4→1e-5 over 200 epochs),
  min_epochs_before_stopping=80 (was 50, gives model more room to recover
  after C51 transition).

- Smoketest config unchanged (lr_decay_type not set → default Constant).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-03-29 18:16:47 +02:00
parent f6caf61252
commit 332b3eb120
2 changed files with 22 additions and 1 deletions

View File

@@ -15,6 +15,8 @@ hidden_dim_base = 64
max_steps_per_epoch = 200
reward_scale = 1.0
huber_delta = 1.0
lr_decay_type = 2
lr_min = 0.00001
[distributional]
num_atoms = 51
@@ -35,7 +37,7 @@ min_replay_size = 500
[early_stopping]
enabled = true
patience = 20
min_epochs_before_stopping = 50
min_epochs_before_stopping = 80
[experience]
gpu_n_episodes = 64

View File

@@ -71,6 +71,10 @@ pub struct TrainingSection {
pub huber_delta: Option<f64>,
/// Adam epsilon — BF16 requires ≥1e-4 (1e-8 rounds to 0 → div-by-zero).
pub adam_epsilon: Option<f64>,
/// LR decay type: 0=constant, 1=linear, 2=cosine (default: 0).
pub lr_decay_type: Option<u32>,
/// Minimum LR for cosine/linear decay (default: 1e-6).
pub lr_min: Option<f64>,
}
/// Epsilon-greedy exploration parameters (DQN-specific).
@@ -653,6 +657,21 @@ impl DqnTrainingProfile {
if let Some(v) = t.adam_epsilon {
hp.adam_epsilon = v;
}
if let Some(decay) = t.lr_decay_type {
let total_steps = t.epochs.unwrap_or(hp.epochs);
let min_lr = t.lr_min.unwrap_or(1e-6);
hp.lr_decay_type = match decay {
1 => crate::trainers::dqn::lr_scheduler::LRDecayType::Linear {
end_lr: min_lr,
total_steps,
},
2 => crate::trainers::dqn::lr_scheduler::LRDecayType::Cosine {
min_lr,
total_steps,
},
_ => crate::trainers::dqn::lr_scheduler::LRDecayType::Constant,
};
}
}
// [exploration]