Field Notes

Engineering

D-FINE-seg gets a semantic segmentation head

D-FINE-seg now supports three tasks on the same DETR-family architecture — and on Cityscapes it benchmarks better than YOLO26 and RF-DETR.

I recently added semantic segmentation to D-FINE-seg, extending the framework beyond object detection and instance segmentation. At Agnify, we have integrated D-FINE-seg into our platform, where its efficient training, export, and inference capabilities support production computer vision applications.

D-FINE-seg is a framework for 3 vision tasks: object detection, instance segmentation and now semantic segmentation too. It allows you to preprocess your data, train the model, export and quantize to various formats (like TensorRT, OpenVINO, etc.) and run efficient inference (maxing out the GPU usage). In this article I am sharing how I added the semantic segmentation task to a DETR-family model - and how the result stacks up on Cityscapes against the two frameworks most people reach for today.

Benchmarks first

I'll get to how the semantic head actually works further down. But let me start with the thing you probably care about most: does it hold up? I trained and benchmarked on Cityscapes, comparing D-FINE-seg in all three tasks against the two frameworks people reach for today - YOLO26 and RF-DETR. Short version: at real-time latency it matches or beats both, from a model with a fraction of the parameters. If you count end-to-end latency (image resize and normalization, forward pass, and postprocessing of boxes/masks), D-FINE-seg is faster across the board - and on accuracy it wins on detection and instance segmentation, and takes the top mIoU on semantic segmentation. The numbers are below. The full protocol and every asymmetry I'm aware of live in the benchmark repo.

A few ground rules first, because they're the whole point:

Everything below is TensorRT 10.13 FP16, batch 1, on 500 Cityscapes val images at original resolution, on an idle RTX 5070 Ti.

Instance segmentation

I'll start here, because it's where the gap is widest and it's the hardest of the three tasks.

model params (M) input conf F1 precision recall IoU e2e ms engine ms
D-FINE-seg S 11.87 640x640 0.5 0.661 0.749 0.591 0.376 4.1 1.91
YOLO26-M 26.98 640x640 0.25 0.599 0.688 0.53 0.312 5.24 2.08
RF-DETR-seg-medium 35.4 432x432 0.35 0.62 0.789 0.51 0.346 16.33 1.8

D-FINE-seg-S lands F1 0.661 - about 6 points over YOLO26-M and 4 over RF-DETR-seg-medium - with under half YOLO26-M's parameters and a third of RF-DETR's, at comparable engine latency.

Detection

model params (M) input conf F1 precision recall IoU e2e ms engine ms
D-FINE-seg S 10.29 640x640 0.5 0.703 0.817 0.617 0.446 2.0 1.38
YOLO26-M 21.79 640x640 0.25 0.691 0.792 0.613 0.432 3.03 1.59
RF-DETR-medium 33.39 576x576 0.35 0.673 0.769 0.599 0.409 10.2 1.45

Here D-FINE-seg-S is the fastest engine and the top F1 (0.703). I'd read this as "a touch more accurate and meaningfully faster".

Semantic segmentation

RF-DETR doesn't offer semantic segmentation yet, so this one is D-FINE vs YOLO26.

model params (M) input mIoU pixel acc e2e ms engine ms
D-FINE-seg S 8.02 640x640 0.728 0.95 1.79 1.5
D-FINE-seg M 16 640x640 0.753 0.954 2.24 2.06
YOLO26-L 17.87 640x640 0.739 0.949 3.56 1.63
YOLO26-M 14.32 640x640 0.733 0.947 3.08 1.16

D-FINE-seg-M takes the top mIoU (0.753), and across the board the two frameworks trade blows within a point or two - D-FINE-seg is right in the mix. I won't oversell it: at the very smallest sizes YOLO26-M is a hair faster on the engine, so this is "competitive, and it leads on mIoU," not a clean sweep. The bigger point is that the task is there at all - same framework, same config, a third capability sitting on top of the detection and instance-seg machinery I already had.

On raw engine latency YOLO26-M edges D-FINE-seg-S. But end-to-end, both D-FINE-seg sizes are faster than both YOLO sizes - and D-FINE-seg-M is also the most accurate (a bigger YOLO26-L still lands below it on mIoU).

Keeping it honest

Now, how it actually works.

Architecture

Quick look at DETRs:

As you can see, DETR-like models are object-centric: sparse queries, matcher, NMS-free. Semantic segmentation on the other hand is a dense, per pixel classification. The good thing is that we have the encoder - it already outputs rich, fully fused multi-scale dense features. Detection head stacks queries on top, but for semantic segmentation we are going to attach a dense head (fully convolutional) straight onto those features and drop the existing decoder entirely. Matcher also is not needed.

What's even better, we already support the instance segmentation task, which means D-FINE-seg already has a lightweight MaskDecoder - a small module that fuses the encoder's features into a single quarter-resolution (stride 4) feature map. The new semantic segmentation head reuses this fuser and adds only a tiny neck (a couple of conv layers) and a 1x1 classifier that labels every pixel, then bilinearly upsamples the logits x4 back to the input resolution. During training we also attach an auxiliary head on the finest encoder feature for deep supervision - it helps learning and costs nothing during the inference.

One more nice trick is that our pretrained instance segmentation fuser weights are transferred directly to the new semantic segmentation head. So you can finetune from instance segmentation weights and only couple of conv layers will be initialized from scratch.

So, the forward path for the segmentation task is: image -> backbone -> hybrid encoder -> (fuser -> neck -> 1x1 classifier -> x4 upsample) -> per-pixel labels

Architecture

Training and export

Losses. Three dense per-pixel terms, weighted 1 / 1 / 0.4:

Void/unlabeled pixels (ignore_index) are dropped from every term, and imbalanced datasets can add an optional per-class weight. No matcher, no query loss - that whole machinery is skipped here.

Training. You fine-tune straight from the instance-segmentation checkpoint - the mask-fuser weights transfer directly, and only the small neck, classifier and aux head start from scratch. From there:

Export. The whole postprocess folds into the graph, so every backend ships the same thing - a single sem_seg output, shape [B, H, W], int32:

That one graph serves ONNX, TensorRT, OpenVINO, CoreML and LiteRT identically - semantic segmentation is actually simpler to export than detection, whose postprocessor OpenVINO can't fully absorb. INT8 works, and the export runs a parity check on per-pixel argmax agreement against PyTorch.

One deliberate call: I argmax at network resolution and resize the labels, rather than upsampling the logits to full resolution first. The alternative gives smoother edges (+0.004 mIoU on Cityscapes) for ~20% more TensorRT latency - not a trade worth making in production.

Visualization

Finally, let's see couple of examples of D-FINE-seg-M inference on the Cityscapes dataset.

Cityscapes inference — Frankfurt 020693

Cityscapes inference — Frankfurt 080391

Written by

Argo Saakyan
Argo Saakyan
Principal Computer Vision Engineer, Agnify

Author of D-FINE-seg. Works on turning always-on camera feeds into operational answers at Agnify. Writes about computer vision, spatial AI, and what the footage on the floor is really telling you.

LinkedIn