pub fn linear_warmup(base_lr: f32, step: u32, warmup_steps: u32) -> Option<f32> {
if warmup_steps == 0 || !base_lr.is_finite() || base_lr <= 0.0 {
return None;
}
let s = step.max(1).min(warmup_steps);
Some(base_lr * (s as f32 / warmup_steps as f32))
}