Offset Boxes
The regression half of training a single-shot detector
- anchors
- assigned_bb
- offsets
A detector doesn't predict boxes directly - it predicts offsets. Given an anchor box and the ground-truth box it's been assigned to, CdlOffsetBoxes computes the small correction that turns the anchor into the target. It's the "teacher" side of the regression loss in any SSD-style detector, and in ComfyDL it's a standalone node you can poke at until the math finally clicks.
This is the offset_boxes function from the Dive into Deep Learning textbook, ported node-for-node. If you've been through Multibox Target you've seen these offsets already - that node computes them internally as its bbox_offset output. This one lets you do it directly, on your own pairs of anchors and boxes, which makes it great for understanding why the numbers look the way they do.
Why the encoding looks weird
Raw anchors and ground-truth boxes have wildly different scales - a big anchor vs. a small object, a wide box vs. a tall one. If the model regressed raw pixel deltas, a 10-pixel shift on a tiny box would be a huge relative error while the same shift on a huge box is noise. So the d2l encoding normalizes:
- center offsets (
dx,dy) - the shift from anchor center to box center, divided by anchor width/height and scaled by 10× - width/height deltas (
dw,dh) - the log ratio of box size to anchor size, scaled by 5×
The 10 and 5 are the classic d2l/SSD magic numbers, chosen so all four components live on a comparable numeric scale. Log-space for sizes is what makes "twice as big" equal "+log(2)" regardless of absolute size.
The inputs
anchors-[N, 4]corner-format anchors(x1, y1, x2, y2).assigned_bb-[N, 4]ground-truth boxes, one per anchor (row i is the box assigned to anchor i; zeros for background anchors).eps- the epsilon that prevents division by zero on degenerate zero-area anchors. Default1e-6; you almost never touch it.
The output is offsets, a [N, 4] tensor of (dx, dy, dw, dh) targets. Feed that into a regression loss (ComfyDL's Squared Loss is right there in TorchOps) and you've got the box-loss half of training. The other half is classification via Multibox Target's class_labels.
Installing ComfyDL
One pack, one tiny dependency. The entire requirements.txt is matplotlib:
cd ComfyUI/custom_nodes
git clone https://github.com/Cynthia-lxx/ComfyDL
cd ComfyDL && pip install -r requirements.txt
Restart ComfyUI; it's under ComfyDL → ObjectDetection. ComfyUI Manager: search "ComfyDL". No models to fetch.
Gotchas
The big one: assigned_bb and anchors must be row-aligned - assigned_bb[i] is the box you want anchor i to chase. If you feed it a raw [M, 4] ground-truth list instead of the per-anchor assignment, you'll silently compute garbage offsets against misaligned rows. The intended upstream is Multibox Target or Assign Anchor→BBox, which produce exactly this aligned form.
Also worth knowing: this node computes the encoding, and it's paired with Offset Inverse, which decodes predicted offsets back into boxes at inference. If you're confused about the round-trip, build both side by side - offsets in one, predictions decoded out the other - and watch a perfect reconstruction when they cancel.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| anchors | TENSOR | — | |
| assigned_bb | TENSOR | — | |
| eps | FLOAT | 0.00001e-12–0.001 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| offsets | TENSOR | — |