Skip to content

Share detector postprocessing across nodes - #89

Closed
klangenk wants to merge 1 commit into
unify-contributing-and-agent-docsfrom
share-detector-postprocessing
Closed

klangenk wants to merge 1 commit into
unify-contributing-and-agent-docsfrom
share-detector-postprocessing

Conversation

@klangenk

Copy link
Copy Markdown
Contributor

Motivation

Every detector node does the same three things with a model's raw output: drop low-confidence predictions, suppress overlapping boxes, and turn what survives into the loop's dataclasses. None of that depends on the model, yet each node repository grew its own copy — and the copies drifted. clip_point is byte-identical in three places across dfine_node and yolov5_node, while clip_box exists in those same three plus a fourth in yolov5_node's trainer that uses a centre-based convention under the same name. A fourth node would have copied it again.

This is the first of several changes moving the model-agnostic parts of node development into this library.

Implementation

  • Add detector/geometry.py with clip_box (top-left anchored), clip_point, and clip_box_centered — the centre-based variant gets its own name so the two conventions can no longer be confused
  • Add detector/postprocess.py with Detection, MIN_BOX_SIZE, bbox_iou, non_max_suppression, post_process and detections_from_xyxy, taken from the dfine_node implementation
  • Unify the two detection containers: to_image_metadata (what a detector node reports) and to_detections (what a trainer's auto-detection pass reports) now share one _append_detections routine, so both paths clip and filter identically
  • Add category_by_index / category_by_name, which raise ValueError with a helpful message instead of IndexError or a bare assert — a model/metadata mismatch is a real error, not a detection to skip quietly
  • Make the scalar arguments of non_max_suppression and post_process keyword-only: transposing origin_h and origin_w was too easy
  • Add learning_loop_node/tests/unit/, the first suite that runs without a Learning Loop, with 31 tests covering clipping, suppression, category resolution and trainer/detector parity
  • Gate the credential-dependent CI jobs on the new unit job, which needs no secrets
  • Document the new modules and the offline suite in AGENTS.md

Notes for the reviewer

  • post_process keeps truncating box corners with int() so detector output stays bit-identical to what nodes reported before this change. detections_from_xyxy, which serves the trainer path, rounds instead — matching the code it replaces. The difference is deliberate and documented.
  • clip_box clamps a corner only at the lower bound, so a box entirely outside the image keeps its origin and collapses to zero size. That is inherited behaviour, unreachable from post_process (which clips first), and it is captured by a test rather than changed here.
  • Unifying the trainer path means auto-detections are now clipped and min-size filtered, which they were not before. This is a deliberate behaviour change on that path; the follow-up dfine_node PR is where it becomes observable.
  • No node consumes this yet. The node PRs are separate and stay pinned to learning_loop_node==0.21.0 until this is released.

⬛ claude-opus-5[1m] · 265k tokens · $6.40

Every detector node does the same three things with a model's raw output:
drop low-confidence predictions, suppress overlapping boxes, and turn what
survives into the loop's dataclasses. None of it depends on the model, yet
each node repository had grown its own copy, and the copies had drifted:
clip_point was byte-identical in three places, while clip_box existed in the
same three plus a fourth that used a centre-based convention under the same
name.

Move that code here as detector/postprocess.py and detector/geometry.py, and
give the centre-based variant its own name (clip_box_centered) so the two
conventions can no longer be confused.

The library also carried two containers for the same detections: a detector
reports ImageMetadata, a trainer's auto-detection pass reports Detections.
to_image_metadata and to_detections now build both from one routine, so the
two paths clip and filter identically instead of diverging.

The scalar arguments of non_max_suppression and post_process are keyword-only:
transposing origin_h and origin_w was too easy to do.

Add tests/unit, the first suite that runs without a Learning Loop, and gate
the credential-dependent jobs on it in CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@klangenk
klangenk changed the base branch from unify-contributing-and-agent-docs to main August 21, 2026 06:42
@klangenk
klangenk changed the base branch from main to unify-contributing-and-agent-docs August 21, 2026 06:44
@klangenk

Copy link
Copy Markdown
Contributor Author

Superseded by #94, which combines all three phases into one PR per repository. The commits are unchanged and still readable in order.

@klangenk klangenk closed this Aug 21, 2026
@klangenk
klangenk deleted the share-detector-postprocessing branch August 21, 2026 14:13
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