74f1737adf
- Validation now runs one forward pass per batch instead of two: through the EMA weights when use_ema=True, through the base weights otherwise. The duplicate base-model pass COCOEvalCallback ran over every validation batch is gone.
- New TrainConfig.eval_base_model (default False) restores the base+EMA comparison; it is inert when use_ema=False, so the default is legal in every configuration.
- TrainConfig.eval_ema_only is deprecated (removal in v2.0): _warn_deprecated_eval_ema_only emits a FutureWarning only for an explicitly supplied non-default value, so reloading a dumped config stays silent. It still requires use_ema=True and now contradicts eval_base_model=True.
- COCOEvalCallback._mirror_ema_metrics_to_primary_keys copies every {split}/ema_<name> scalar in callback_metrics onto {split}/<name> in the branch where the base metric accumulated nothing, so schedulers, early stopping, checkpoint monitors and dashboards watching the primary key keep receiving a real number. Mirroring the whole prefix rather than a key list covers box, segmentation and keypoint monitors alike; per-class AP goes through pl_module.log only and stays under {split}/ema_AP/<class>.
- BestModelCallback gains evaluates_base_model, wired from trainer.py as tc.eval_base_model or not enable_ema. When false it disables both the regular monitor guard and the smoothing accumulator, because the mirrored primary key carries the EMA score while that track saves base weights. The EMA track still runs and on_fit_end promotes its checkpoint.
- RFDETRModelModule._resolve_eval_model now branches on eval_base_model; the existing fallbacks cover EMA warm-up, use_ema=False and an unattached Trainer.
- val/F1 and val/loss follow the same single forward and therefore describe the EMA model on a default run; recorded in CHANGELOG, the 1.9 to 1.10 migration section and the validation-performance docs.
---------
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>