Skip to content

Let a recipe train at the precision its upstream reference uses - #10

Merged
EHxuban11 merged 1 commit into
rf100vl-harnessfrom
ec-fp16-precision
Aug 10, 2026
Merged

EHxuban11 merged 1 commit into
rf100vl-harnessfrom
ec-fp16-precision

Conversation

@EHxuban11

Copy link
Copy Markdown
Contributor

RF100-VL forced every family to fp32. For EdgeCrafter that matches neither its
authors nor our own library, so the ec recipe now runs fp16, and the harness
records which precision produced a result.

Why ec is fp16

  • Upstream ecdetseg/configs/ecdet/ecdet.yml sets use_amp: True with a
    GradScaler, and the train loop wraps the forward in torch.autocast with
    no dtype, which is fp16 on CUDA. All four size configs __include__ it, so
    fine-tuning inherits it too.
  • LibreYOLO's own ECConfig sets amp: bool = True and overrides no
    amp_dtype, so it inherits the base "float16".
  • LibreYOLO enables the GradScaler for fp16 and skips it for bf16
    (trainer.py:1599), so fp16 gets the loss scaling it needs.

Three bugs this also fixes

amp_dtype ignored the recipe. It was "amp": precision == "bfloat16" with
a hardcoded "amp_dtype": "bfloat16", so an fp16 recipe would have trained in
fp32 while its stats and submission claimed fp16. Both now come from one
PRECISION_AMP_DTYPE table.

Two separate gates rejected fp16. load_recipe refused it, and
_recipe_repro independently flagged it as mismatched training metadata,
which would have invalidated a submission after a campaign had already run.

No submission recorded its precision. config omits it and
runtime.precision is assemble_result's default, never passed by the
RF100-VL path, so every published run says fp32 whatever it did. There is now
rf100vl.training_precision, read from the per-dataset stats, and checkpoints
that disagree produce an invalid_reason instead of passing unnoticed.

Tests

162 passed. New coverage: the dtype table across all three precisions
(the regression above), the ec recipe pinned to fp16, and the existing
all-families check turned into an allowlist so a new family cannot pick a
non-fp32 precision without naming a reason.

Code provenance

Original code written for this PR by me, an AI agent. Precision facts were
read from two sources and are cited above: the EdgeCrafter reference
implementation at Intellindust-AI-Lab/EdgeCrafter (Apache-2.0), inspected
only to determine what precision it trains at, with no code copied or adapted;
and LibreYOLO's own training/config.py and training/trainer.py.

Unrelated finding while tracing that: THIRD_PARTY_NOTICES.txt in the
libreyolo repo attributes EdgeCrafter to github.com/EC-codehub/EdgeCrafter,
which 404s. The live repo appears to be Intellindust-AI-Lab/EdgeCrafter.
Worth correcting there, separately from this PR.

RF100-VL forced every family to fp32. For EdgeCrafter that matches neither
the reference implementation, which sets use_amp with a GradScaler in
ecdetseg/configs/ecdet/ecdet.yml, nor LibreYOLO's ECConfig, which enables amp
and inherits the float16 dtype. Training a model at a precision nobody who
built it uses is its own distortion, so allow fp16 and record what ran.

- Derive amp and amp_dtype from one PRECISION_AMP_DTYPE table. They were
  computed as `precision == "bfloat16"` and the literal `"bfloat16"`, so an
  fp16 recipe would have silently trained in fp32 while its stats and
  submission claimed fp16.
- Accept fp16 in both gates. The recipe validator rejected it outright, and
  the evaluation path separately flagged it as mismatched training metadata,
  which would have invalidated the submission after a successful campaign.
- Record the precision. Nothing in a submission said which one produced it:
  `config` omits it and `runtime.precision` is the assemble_result default,
  never passed by the RF100-VL path. `rf100vl.training_precision` now carries
  it, read from the per-dataset stats, and disagreement across checkpoints
  becomes an invalid_reason rather than passing unnoticed.
- Set the ec recipe to fp16 and pin the intent in tests: an allowlist names
  every family that is deliberately not fp32, so the next one has to justify
  itself instead of drifting.

LibreYOLO enables the GradScaler for fp16 and skips it for bf16
(trainer.py:1599), so fp16 gets the loss scaling it needs.
@EHxuban11
EHxuban11 merged commit ebba0fc into rf100vl-harness Aug 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant