This section is about vision models that say where things are, not only what an image shows. A classifier reads an image and returns one label. Most real uses of vision need more. A driving system needs a box around every car and pedestrian. A radiology tool needs the outline of a tumor, pixel by pixel. A photo editor needs the exact shape of the object the user just clicked. These are dense prediction tasks, so called because the model makes a prediction at every location of the image rather than one for the whole image. They run most deployed vision systems, and interviews for vision roles probe them in detail.
The input side is already built. The last section ended with backbones that turn an image into feature maps. A feature map is a grid of vectors, and each vector describes one small region of the image. Its stride is the number of pixels that one step on the grid covers. A plain ViT gives one map at stride 16, one vector per 16 by 16 patch. Hierarchical backbones, which shrink the grid stage by stage as a CNN does, give a pyramid of maps at strides 4, 8, 16, and 32. A classifier averages such a map into one vector and throws the layout away. This section keeps the map and puts small networks on it, called heads, that output boxes and masks.
Three things change when the output stops being one label. First, the output becomes a set whose size depends on the image, zero pedestrians or forty. Second, the set has no natural order, so "the third box" means nothing, and a loss must not care which output slot predicted which object. Third, a metric must decide which prediction belongs to which object before it can score anything. That matching step is most of the difficulty of measuring a detector.
We take these in order. First we measure how much two boxes overlap. Then we build the classical detector piece by piece, from fixed reference boxes to the rule that deletes duplicate boxes. Next comes DETR, a Transformer that predicts the whole set of objects at once and needs none of those hand-made pieces. Then we compute COCO average precision, the standard detection score, exactly. Last come segmentation heads, their metrics, and SAM, SAM 2, and SAM 3, models that segment whatever you click on or name.
Four tasks, four kinds of output
The four standard dense tasks differ only in what they output. Picture a street photo with two touching cars, a road, and the sky. Detection draws a scored box around each car. Semantic segmentation colors every pixel by its class, so the two touching cars become one blob of car pixels. Instance segmentation gives each car its own mask. Panoptic segmentation does both at once. Every pixel gets a class, and every car pixel also says which car it belongs to.
The standard benchmark for all four tasks is COCO, Common Objects in Context (Lin et al. 2014). It has about 118,000 training images of everyday scenes, labeled with 80 object categories, plus stuff classes for panoptic segmentation.
A fifth kind of dense output is a real number per pixel instead of a class. The main example is monocular depth estimation, the distance from the camera at every pixel, predicted from a single image. Surface normals are another. These tasks use the same backbones and upsampling heads as semantic segmentation, with a regression loss in place of the per-pixel classifier.
A box is four numbers, and three conventions for those numbers are in common use. Mixing them up is one of the most common bugs in detection code, because every mix-up still produces plausible-looking numbers.
Measuring overlap, IoU and GIoU
To score a predicted box against a true one, we need a number that is 1 when the boxes coincide, 0 when they do not touch, and the same for a small object and a large one. A pixel error is not that number. Five pixels off is terrible for a 10-pixel bird and irrelevant for a 500-pixel bus. The shared area divided by the total area covered has all three properties.
Here it is with numbers. Take two 2 by 2 squares, one with its corner at the origin and one shifted by 1 in both directions. They share a 1 by 1 square. Together they cover 4+4−1=7 square units, so the ratio is 1/7. This ratio is called intersection over union.
In plain words, IoU is the fraction of the combined area that both boxes cover. GIoU, the generalized IoU, subtracts a penalty, the fraction of the enclosing box that neither box covers. The penalty is large when the boxes are far apart.
The penalty is what makes GIoU useful as a training loss. Suppose a predicted box misses its target entirely. Then ∣A∩B∣=0 and ∣A∪B∣=∣A∣+∣B∣, so
IoU=0,GIoU=0−∣C∣∣C∣−∣A∣−∣B∣=∣C∣∣A∣+∣B∣−1.
Slide the prediction toward the target and the IoU stays at 0 the whole way. Its gradient with respect to the box coordinates is exactly zero, so a loss of 1−IoU gives a missing prediction no signal at all. The GIoU rises as the enclosing box shrinks, so 1−GIoU pulls the prediction toward its target. As the boxes move infinitely far apart, ∣C∣→∞ and the GIoU tends to −1, which is why its range is open at −1.
Both IoU and GIoU are scale invariant. Scale both boxes by the same factor and every area scales by the square of that factor, so the ratios do not change. An L1 distance between coordinates, the sum of the absolute differences, does not. It charges five pixels of error the same on the 10-pixel bird and on the 500-pixel bus. DETR, later in this section, uses both kinds of term in its loss.
The vectorized version below compares an (n,4) array of boxes with an (m,4) array and returns all nm pairs at once, by broadcasting. Each line is one piece of the definition. The clamp at zero is the line people forget.
Python · cell 1
In practice, IoU is the measure behind every later step of this section. It labels training examples, decides which duplicate boxes to delete, and decides whether a detection counts as correct. An interviewer who asks you to write it expects the clamp, and often asks next why a box loss needs GIoU.
Core
Pairwise IoU and GIoU
Write box_iou(A, B) and box_giou(A, B). A has shape (n, 4) and B has shape (m, 4), both in corner form (x1,y1,x2,y2) with x2>x1 and y2>y1. Each function returns an (n, m) array, with entry (i,j) comparing box i of A with box j of B, and uses no Python loops over boxes. The tests check the worked example, boxes that do not overlap, boxes that are diagonal neighbors (where a missing clamp gives a positive overlap), and random boxes.
import numpy as np
def box_iou(A, B):
"""A: (n, 4), B: (m, 4) boxes as (x1, y1, x2, y2). Return the (n, m) IoU matrix."""
raise NotImplementedError
def box_giou(A, B):
"""Same inputs. Return the (n, m) generalized IoU matrix."""
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Classical detectors, from anchors to RoIAlign and focal loss
Before 2020, nearly every detector turned detection into a very large number of small questions, each asked at a fixed place in the image. Is there an object near this place? If so, how should a reference box at this place move to fit it? The vocabulary of that design is still everywhere, including inside the detectors that replaced it, and interviewers still ask about every piece.
Anchors and box deltas
An anchor is a fixed reference box placed at a location of the feature map. The network does not predict a box from nothing. For each anchor it predicts a score, "is there an object here", and a small correction that moves the anchor onto the object. The classic two-stage detector, Faster R-CNN (Ren et al. 2015), which we assemble below, places 9 anchors at every position. They are 3 sizes (areas of 1282, 2562, and 5122 pixels) times 3 aspect ratios (height over width of 1, 2, and 1/2).
The correction is measured relative to the anchor. Take an anchor 128 pixels wide centered at x=100, and an object 96 pixels wide centered at x=116. The network is asked for the shift as a fraction of the anchor's width, 16/128=0.125, and for the logarithm of the width ratio, log(96/128)=−0.288. In general, with the superscript a marking the anchor and (xc,yc,wb,hb) the object's box in center form,
The vector Δ=(Δx,Δy,Δw,Δh), the box deltas, is what the network regresses. Dividing by the anchor's size makes the targets the same for a small anchor and a large one. The logarithm makes doubling and halving equally large errors, since log2=−log21. Inverting each equation gives the decoder that turns predicted deltas back into a box,
and the exponential keeps every decoded width and height positive.
Which anchors count as positives is decided by IoU. In Faster R-CNN's first stage, an anchor whose IoU with some object exceeds 0.7 is a positive. So is the anchor with the highest IoU for each object, so that no object is left without one. An anchor whose IoU with every object is below 0.3 is a negative, and the rest are ignored in training.
Detectors split into two kinds by what they do with these scores. A two-stage detector uses them only to propose regions, then looks at the best proposals again and classifies them, as we will see below. A one-stage detector classifies every anchor directly into the K classes. RetinaNet (Lin et al. 2017b), the one-stage detector we meet with focal loss, labels anchors with IoU at least 0.5 as positives and below 0.4 as negatives, and ignores the band between.
In an interview, expect to write the encoder and decoder, and to say why the width delta is a logarithm.
Warm-up
Encoding and decoding box deltas
Write encode_deltas(boxes, anchors) and decode_deltas(deltas, anchors). Both boxes and anchors have shape (n, 4) in corner form (x1,y1,x2,y2), and row i of boxes is the target for row i of anchors. Widths are x2−x1 and heights y2−y1. encode_deltas returns the (n, 4) array of deltas (Δx,Δy,Δw,Δh) defined above. decode_deltas inverts it and returns corner boxes. The tests check the worked example, an exact round trip in both directions, and the usual slips (corners used as centers, a missing logarithm, dividing by the object's size instead of the anchor's).
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Feature pyramids
Objects in one image range from a few pixels to the whole frame. So small anchors should read fine feature maps, where each vector covers a few pixels, and large anchors should read coarse ones. A CNN backbone already has maps at several strides. But the fine maps come from early layers, which know little about what objects are. The feature pyramid network, FPN (Lin et al. 2017a), passes that knowledge down from the coarse maps.
It works from the top down. Start from the coarsest map, at stride 32. Upsample it by 2 with nearest-neighbor interpolation, which copies each vector into a 2 by 2 block. Add a 1×1 convolution of the backbone's next finer map, called the lateral connection. Repeat down to stride 4, and smooth each sum with a 3×3 convolution. Every level has the same width, 256 channels, so one shared head can run on all of them. Each level now combines the fine resolution of its own stage with what the deepest stage knows about objects.
A proposed region, called a region of interest, reads one level, chosen by its size. FPN numbers its levels so that level k has stride 2k. It sends a region of width wb and height hb to level
k=⌊4+log2224wbhb⌋,
clamped to the levels that exist. A region 224 pixels on a side reads level 4, stride 16. A 112-pixel region reads level 3, stride 8, and a 448-pixel region reads level 5, stride 32. Each halving of the side moves one level finer, so every region that the clamp does not touch spans between 14 and 28 cells on a side of the grid it reads.
In practice, the pyramid is what lets one detector find both a distant pedestrian and a nearby bus. Its gains are largest on small objects. An interviewer may ask why the fine levels need the top-down path at all, and the answer is that early layers see edges and textures but not yet objects.
A plain ViT has only one map, at stride 16. §27.5 showed how to build a pyramid from that one map anyway, the simple feature pyramid of ViTDet (Li et al. 2022a). Max pooling gives stride 32. Transposed convolutions, the learned upsampling of §0.8, give strides 8 and 4. Combined with masked-autoencoder (MAE) pretraining, which teaches a ViT to fill in hidden patches, that made plain ViTs competitive backbones for dense tasks again.
Non-maximum suppression
A dense detector fires many overlapping boxes on each object, because every anchor near the object learns to say "object". Non-maximum suppression, NMS, keeps the best box of each cluster and deletes the rest. It is greedy. Keep the highest-scoring box, delete everything that overlaps it too much, and repeat with what is left.
NMS is a heuristic, a hand-set rule rather than something the network learns, and it has two weaknesses. It has one global threshold, so it cannot tell two detections of one object from two detections of two overlapping objects. And it is not differentiable, so the network cannot learn to avoid the duplicates it creates. The cell below builds a small crowd. Two people stand close together, with true boxes that overlap at IoU 0.71, and a third person stands apart. Each person gets four jittered detections, and we run NMS at several thresholds.
Python · cell 2
At 0.3 and 0.5, the best box of the first person suppresses every box of the second, because the two people overlap more than the threshold allows. At 0.7 all three people survive with no duplicates, and at 0.8 and above duplicates leak through. No single threshold is right for every scene, and in a dense crowd the window where one works can vanish.
Soft-NMS (Bodla et al. 2017) lowers the scores of overlapping boxes instead of deleting them. Its linear form multiplies the score of a box bi by 1−IoU(bi,bkept) whenever that IoU exceeds t. Its Gaussian form multiplies every score by exp(−IoU2/σ) for a width σ. The second person survives with a lower score instead of vanishing. That helps in crowds, but the heuristic remains. DETR, below, removes it.
The widget puts two people side by side and lets you push them together. The strip beside the picture marks every threshold that finds both people with no duplicate, and from an overlap of 0.7 on there is none. Switching to soft-NMS replaces deletion by the linear score decay, and a box counts as kept while its score stays at least 0.3. It finds both people up to an overlap of about 0.68.
Can one NMS threshold tell two overlapping people from one person detected twice?
Two people, gray, with four detections each. Bold boxes survive suppression, labeled with their final scores.
Loading interactive figure…
Interview
Non-maximum suppression, class-aware
Write nms(boxes, scores, iou_thresh, classes=None) for corner boxes of shape (n, 4) and scores of shape (n,). Return the indices of the kept boxes as an integer array, highest score first. Suppress a box only if its IoU with a kept box is strictly greater than iou_thresh, the rule torchvision uses. When classes is given, boxes of different classes never suppress each other. Break ties in score by input order, with a stable sort. Coordinates may be negative, as they are for decoded boxes before clipping, and an empty input returns an empty array.
import numpy as np
def nms(boxes, scores, iou_thresh, classes=None):
"""boxes (n, 4) corners, scores (n,), classes (n,) ints or None.
Return the indices of the kept boxes, highest score first."""
return np.argsort(-np.asarray(scores)) # placeholder that keeps everything
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Two-stage detectors and RoIAlign
A two-stage detector splits detection into two questions. Where might an object be? And what exactly is it? Faster R-CNN (Ren et al. 2015) answers both from one shared backbone feature map.
Stage one, the region proposal network (RPN). A 3×3 convolution slides over the feature map. Two 1×1 convolutions then predict, for each of the 9 anchors at each position, an objectness score (object or background, with no class) and four deltas. A 1000×600 image at stride 16 has about 60×40×9≈20,000 anchors. At inference the deltas are decoded, the boxes are clipped to the image, and NMS at IoU 0.7 thins them to about 2,000 proposals. The top 300 go to the second stage at test time.
Stage two, the RoI head. Each proposal is a region of interest, or RoI. For each one, the head extracts a small fixed-size grid of features, 7×7 for the box head, runs a few layers on it, and predicts K+1 class scores (the K classes plus background) and a box correction for each class. Class-wise NMS then removes duplicates among the refined boxes.
Two-stage detectors handle class imbalance by filtering. The RPN discards almost all the background before the second-stage classifier sees it. One-stage detectors have no such filter, and focal loss, in the next subsection, does that job for them.
The interesting part is how the head extracts features for a proposal. A proposal is a box in continuous image coordinates, and the feature map is a grid of cells at stride s. The first method, RoIPool from Fast R-CNN, rounds twice. Take a proposal whose left edge is at x=57 pixels, on a stride-16 map. Its grid coordinate is 57/16=3.56, and RoIPool rounds it to cell 4, which starts at pixel 64, 7 pixels away. Then it splits the rounded box into 7×7 bins, rounds the bin edges again (down for the start, up for the end), and takes the maximum over the cells of each bin.
The first rounding moves an edge by up to half a cell, 8 pixels at stride 16, and the second adds up to another cell. A classifier barely notices, since a few pixels of shift do not change what the object is. A mask does notice. A mask predicted from shifted features lands shifted on the image. Mask R-CNN (He et al. 2017), which extends Faster R-CNN to predict a mask for every region, removed the rounding with RoIAlign.
In plain words, RoIAlign treats the feature map as a continuous function. It reads that function at evenly spaced points inside each bin and averages them. When a box moves by a tenth of a pixel, its sample points move by a tenth of a pixel too, and the features change smoothly instead of jumping by a whole cell. Mask R-CNN uses ns=2, four points per bin, and found that taking the max or the average over those points scores almost the same (30.2 and 30.3 mask AP).
Here is a tiny case. A 7×7 grid of bins over a box 80 pixels wide on a stride-16 map makes each bin 80/16/7=0.71 cells wide. RoIPool must round that to whole cells, so some bins read one cell and others two. RoIAlign samples each bin at two points 0.36 cells apart and reads between cells by interpolation.
The offset of one half is a classic interview probe. Feature cell j summarizes the patch of the image centered at pixel (j+21)s. So image coordinate x corresponds to grid coordinate x/s−21, the convention under which index j means "the center of cell j". The original Mask R-CNN code left out the −21 and shifted every feature by half a cell. The detection libraries Detectron2 and torchvision fixed this with the flag aligned=True and kept aligned=False for the old behavior.
The cell measures how far RoIPool's bins land from where they should be, along one axis. It compares the center of the cells each bin reads with the exact center of the bin.
Python · cell 3
On the 80-pixel box, the RoIPool bins sit 6 to 24 pixels to the right of where they belong. Over random boxes the error averages about half a stride and reaches a full stride at the 95th percentile, 17 pixels at stride 16 and 35 at stride 32. RoIAlign with aligned=True has no such error, because its sample points sit symmetrically inside each exact bin. With aligned=False, every bin is off by exactly half a cell, 8 pixels at stride 16. For a 50-pixel object, a 17-pixel shift is a third of its width.
With aligned features in hand, Mask R-CNN adds a third branch to the RoI head. It predicts a 28×28 mask for each region from a 14×14 RoIAlign grid. It predicts one mask per class, each through a per-pixel sigmoid, and the loss uses only the mask of the region's true class. The total loss per RoI is the sum of three terms, Lcls+Lbox+Lmask, for the class, the box, and the mask.
Interview
RoIAlign from scratch
Write roi_align(feat, box, out_size, spatial_scale, sampling_ratio=2, aligned=True) exactly as defined above. feat has shape (C, H, W), and box is one box (x1,y1,x2,y2) in image pixels. out_size is an integer or a pair (p_h, p_w), and the result has shape (C, p_h, p_w). Use the offset o=21 when aligned is true and 0 otherwise. In each bin, sample sampling_ratio points along each axis at the centers of a regular subgrid, interpolate bilinearly with torchvision's border rule, and average. The tests compare against a reference loop that matches torchvision.ops.roi_align. They catch a rounded box (RoIPool's quantization), a wrong half-pixel offset, swapped x and y, a missing spatial scale, and sample points at the corners of the subgrid instead of its centers. Every test box spans at least one feature cell.
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Focal loss, and why easy negatives matter
A one-stage detector faces an extreme class imbalance. RetinaNet scores about 100,000 anchors per image, and only a tiny fraction of them overlap an object. Almost every anchor is an easy negative, background that the network already rejects with high confidence.
Recall from §0.5 that cross-entropy, the standard classification loss, charges minus the logarithm of the probability the model gave to the right answer. An easy negative that the model calls background with probability 0.99 costs −log0.99=0.010. That is tiny, but 99,900 of them add up to about 1,000. A hundred hard positives at probability 0.5 cost 100⋅log2=69. The easy negatives carry 93.5 percent of the loss. They carry 95 percent of its gradient too, since each sends back a gradient of 1−pt, 0.01 against 0.5 for a hard positive. So training spends its effort on background it has already learned.
The fix is to shrink the loss of examples the model already gets right. To write it, take one anchor and one class, with label y∈{0,1}, logit x, and predicted probability p=σ(x), where σ is the sigmoid. Define pt=p if y=1 and pt=1−p otherwise, the probability assigned to the correct answer. The subscript t stands for "true", as in the focal loss paper, and is not the IoU threshold. Cross-entropy is then −logpt.
In plain words, focal loss is cross-entropy multiplied by (1−pt)γf, a factor near 1 for a hard example and near 0 for an easy one. With γf=2, an example at pt=0.9 has its loss cut 100 times, and one at pt≈0.968 about 1,000 times. An example at pt≤0.5 loses at most a factor of 4. The bias initialization serves the same goal from the first step. If every anchor started at probability 0.5, the 100,000 background anchors would produce a huge loss and an unstable first update.
What matters for training is the gradient, the signal each example sends back to the network. Here is its exact form.
Substituting dpt/dxt=pt(1−pt) gives γf(1−pt)γfptlogpt−(1−pt)γf+1, which factors as stated. Setting γf=0 gives the cross-entropy gradient −(1−pt), and dividing gives the ratio. As pt→1, −logpt=(1−pt)+O((1−pt)2), so the fraction tends to 1 and the ratio to (1+γf)(1−pt)γf. ■
In plain words, compared with cross-entropy, focal loss shrinks the gradient of an easy example by roughly (1+γf)(1−pt)γf. With γf=2, an anchor the network already gets right at 99 percent contributes about 3,300 times less gradient, while a misclassified anchor keeps most of its gradient. The cell checks the formula against a finite difference. Then it splits the loss of one image into its easy-negative and hard-positive parts.
Python · cell 4
Under cross-entropy, the 99,900 easy negatives carry 93.5 percent of the loss of this image. Under focal loss they carry 1.7 percent, and the hundred hard positives get the attention. With focal loss, the one-stage RetinaNet beat the two-stage detectors of its time, reaching 39.1 AP on COCO test-dev with a ResNet-101-FPN backbone (Lin et al. 2017b). Focal loss outlived anchors. DETR's descendants use it for their class heads, and SAM uses it for its masks.
The plot shows the mechanism. The left panel is the loss and the right panel the size of its gradient with respect to the logit, both against pt, for four values of γf. The gradient axis is logarithmic, so equal vertical gaps are equal factors.
Python · cell 5
In the shaded band of easy examples, the curves separate by orders of magnitude, about (1+γf)(1−pt)γf as derived. Below pt=0.5 they stay within a small factor of each other. A larger γf silences easy examples more, but it also starts to mute moderately hard ones. That is why γf=2 won the paper's ablation, with 34.0 AP against 32.2 at γf=5 and 31.1 for cross-entropy with the best αf. An interviewer will ask what γf does, why the bias starts at −4.6, and how a two-stage detector solves the same problem without focal loss.
Anchor-free heads and label assignment
Anchors bring their own hyperparameters (sizes, ratios, IoU thresholds), and most anchors are wasted. An anchor-free detector drops them. In FCOS (Tian et al. 2019), every location of every pyramid level is mapped back to an image point (x,y). A point that falls inside a ground-truth box (x1,y1,x2,y2) is a candidate positive. Instead of deltas from an anchor, the head regresses the distances from the point to the four sides of the box,
l∗=x−x1,t∗=y−y1,r∗=x2−x,b∗=y2−y,
all positive for a point inside the box. Each object goes to one pyramid level by its size, small objects to fine levels and large ones to coarse levels.
Points near a box's edge produce poor boxes. So a one-layer branch predicts center-ness,
In plain words, center-ness is 1 at the exact center of a box and falls toward 0 at an edge. A point at distances (l∗,t∗,r∗,b∗)=(10,30,30,10) scores 31⋅31=31. The branch is trained with binary cross-entropy, and its output multiplies the class score at test time, so NMS ranks central boxes first. In the FCOS ablation it raised COCO AP from 33.5 to 37.1. Classification uses focal loss, so FCOS is a RetinaNet without anchors.
The lesson interviewers look for is that anchors were never the essential part. What decides accuracy is label assignment, the rule that picks which anchors or points are positives for each object.
DETR, detection as set prediction
The pipeline above has many hand-designed parts, the anchor sizes, the IoU thresholds that label anchors, and the NMS threshold. Carion et al. (2020) asked whether a Transformer could output the set of objects directly, so that none of these parts would be needed. Their model, DETR (DEtection TRansformer), is short to describe.
A ResNet-50 backbone maps the image to a feature map of C=2048 channels at stride 32. A 1×1 convolution reduces it to width d=256, and the map is flattened into a sequence of tokens, one per grid location. A standard Transformer encoder with 6 layers and 8 heads mixes those tokens. It knows where each token sits through fixed 2-D sine-cosine position encodings, the idea of §27.1 applied to a CNN's grid, with half of the d channels encoding the row and half the column.
The decoder produces the objects. Recall from §4.6 that in cross-attention a set of query vectors reads from another sequence, and that a model can learn its own query vectors, one per output slot. DETR's decoder has Nq=100 such slots, whose learned vectors are called object queries. Over 6 layers, each slot reads the image through cross-attention and talks to the other slots through self-attention. It ends as a description of one object, or of nothing.
A shared head turns each of the Nq outputs into two things. One is a distribution over K+1 classes, the K real ones plus a "no object" class written ∅. The other is a box in normalized center form, from a 3-layer MLP and a sigmoid. Every query outputs a box. Most of them should say ∅.
Here is one real image followed through every stage, with its shapes.
The cell checks the shapes and shows why DETR reads only the stride-32 map. Attention scores every pair of tokens, so its cost grows with the square of the token count.
Python · cell 6
At stride 32 an attention map per head takes about 3 MB. At stride 8 the same image has 13,400 tokens, and every head of every encoder layer would score 180 million pairs, about 720 MB in 32-bit floats. That is 248 times the stride-32 cost, which is why DETR gave up the fine map and, with it, much of its accuracy on small objects.
The hard part is the loss. The model outputs 100 predictions in a fixed order of slots. The image contains m objects in no order at all, on COCO usually a handful and rarely more than a few dozen. Nothing says which slot should predict which object. DETR's answer is to find, for each training image, the one-to-one assignment of predictions to objects that fits best. Then it trains each prediction toward the object it was assigned.
A tiny case shows why this works. Suppose two queries both sit on the same cat, one with a tight box at 80 percent confidence and one with a looser box at 60 percent. The best assignment gives the cat to the first query. The second has no object left, so it is trained to say "no object". The loss itself punishes the duplicate, so the model learns to output one box per object.
In plain words, first find the cheapest one-to-one assignment of predictions to objects, under a cost that mixes class probability and box distance. Then apply ordinary classification and box losses to the matched pairs, and train every unmatched prediction to say "no object".
Four details in that definition are deliberate, and interviewers ask about each.
Probabilities in the matching, log-probabilities in the loss. The matching cost uses −p^, which lies in [−1,0], the same order of size as the box terms. A −logp^ term would be unbounded, and one confident class score could override the geometry. Carion et al. report that probabilities match better. The loss itself uses −logp^ because that is cross-entropy.
The constant in the GIoU term. The paper writes the box cost as 1−GIoU and the code as −GIoU. Every matching pairs exactly m objects, so the two costs differ by the constant mλgiou for every π and have the same minimizer.
The weight 0.1 on ∅. With 100 queries and a handful of objects, about 95 percent of the class terms are "no object". Down-weighting them by 10 is the simplest fix for that class imbalance, a fixed weight where focal loss uses one that depends on how easy each example is. Carion et al. compare it to the way Faster R-CNN subsamples background proposals. The padded entries cost nothing to match, since their cost does not depend on the prediction.
Auxiliary losses. The same prediction head and the same Hungarian loss are applied after every one of the 6 decoder layers, which helps the decoder output the right number of objects. At inference only the last layer is used.
∂ Why the Hungarian loss ignores the order of the queries
(1) Let ρ be a permutation and define the permuted predictions y^i′=y^ρ(i). A matching π of the permuted list pairs yj with y^π(j)′=y^ρ(π(j)), so its cost equals the cost of the matching ρ∘π of the original list. The map π↦ρ∘π is a bijection of the set of all permutations onto itself (its inverse is π↦ρ−1∘π), so the two minimizations range over the same set of costs and have the same minimum. If the original minimizer π^ is unique, the permuted minimizer is ρ−1∘π^, which pairs every object with the same prediction as before, so every term of the loss is unchanged. (2) Minimizing ∑jCj,π(j) over permutations for a square cost matrix C is the linear assignment problem, which the Hungarian method of Kuhn (1955), in its later O(n3) form, solves exactly. Here n=Nq. ■
In plain words, shuffling the queries cannot change the loss, and the best matching takes one cubic-time solve per image, not a search over all Nq! orderings. The padded columns make the square problem equivalent to a rectangular one. Choose m distinct predictions for the m real objects at minimum total cost, and send the remaining Nq−m predictions to ∅. scipy.optimize.linear_sum_assignment solves the rectangular problem directly, with a shortest augmenting path algorithm. For Nq=100 and a few dozen objects it takes well under a millisecond on a CPU, which is why DETR runs it on the CPU for every image of every batch.
Python · cell 7
The widget lets you play the matcher. Unlike the example above, its confident query is the loose one. Its q0 is a loose box on cat A at confidence 0.8, and its q1 a second box on A at 0.6, the right size but off center. Drag q1 onto A and watch the moment the assignment flips. Watch the margin to the runner-up matching too. A small margin means a tiny change in one box can hand an object to a different query.
How does DETR decide which prediction answers which object?
Solid boxes are objects and dashed boxes predictions. Lines show the matching, and gray predictions match no object. Drag a prediction, or set its class and confidence.
Loading interactive figure…
Interview
DETR's matching and Hungarian loss
Write detr_match_and_loss(logits, pred_boxes, gt_labels, gt_boxes, l1=5.0, giou=2.0, eos_coef=0.1) for one image, and return (pred_idx, gt_idx, loss).
The inputs are these. logits has shape (N_q, K + 1), and its last column is the no-object class. pred_boxes has shape (N_q, 4) and gt_boxes has shape (m, 4), both in normalized center form (xc,yc,wb,hb). gt_labels holds m integers in 0..K-1. Assume 1≤m≤Nq.
Build the (N_q, m) cost matrix −p^i(cj)+λL1∥⋅∥1+λgiou(1−GIoU), with softmax probabilities (computed stably, so large logits cannot overflow) and with GIoU computed on corners, and match with scipy.optimize.linear_sum_assignment. The loss has three terms. The class term is ∑iwi(−logp^i(ti))/∑iwi over all queries, where ti is the matched class or no object, and wi is eos_coef for no object and 1 otherwise. The L1 term is l1 times the summed L1 distance of the matched pairs, divided by m. The GIoU term is giou times the summed 1−GIoU of the matched pairs, divided by m.
import numpy as np
from scipy.optimize import linear_sum_assignment
def detr_match_and_loss(logits, pred_boxes, gt_labels, gt_boxes, l1=5.0, giou=2.0, eos_coef=0.1):
"""logits (N_q, K + 1), last column = no object. Boxes (cx, cy, w, h) in [0, 1].
Return (pred_idx, gt_idx, loss)."""
raise NotImplementedError
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
In PyTorch, a DETR head is a set of learned queries, one decoder layer, and two small heads, and the whole training step fits on a page. The block below overfits one image with three objects. With so few objects, it finds the matching by brute force over all 10⋅9⋅8=720 ordered choices, which gives the same answer as the Hungarian method. Real code calls linear_sum_assignment on the detached cost matrix, since the matching itself is not differentiated.
The block makes one more simplification. PyTorch's built-in decoder layer has no argument for positional encodings. So the block feeds the learned queries in as the decoder's input, as §4.6 introduced them, instead of starting from zeros and adding the queries in every layer as DETR does.
🔥 In PyTorchfor a machine with PyTorch
Three queries end up confident, with the right classes and boxes, and the other seven say "no object". On one image, the matching settles at the first step. Across a dataset it does not, and that is DETR's weakness.
Why DETR converges slowly, and what fixed it
DETR's slow training has two causes. First, every object query starts as an arbitrary vector, and its cross-attention spreads almost evenly over all the image tokens. Each query must learn from scratch where to look. Global attention over a large map is also expensive, as the walkthrough above measured, which is why DETR could afford only stride 32 and lost small objects. Second, the matching is unstable early in training. When predictions are poor, many queries have similar costs for the same object, so the assignment flips from one step to the next. A query is trained toward a cat in one step and toward "no object" in the next.
The descendants of DETR fix one cause or both, with three ideas. First, let each query attend to a few points instead of the whole map. Second, give each query an explicit box to refine, and add training queries whose targets are known without matching. Third, match each object to several queries during training only. Together they cut training from 500 epochs to 12, with higher accuracy, and made DETRs the strongest detectors. An interviewer who asks about DETR almost always asks this next.
The self-supervised backbones that power these detectors, trained on images without labels, are the subject of Chapter 28. The point here is structural. The strongest published detectors of recent years are set predictors trained with a matching loss. The pyramid they read comes either from a hierarchical backbone or from a simple pyramid built on a plain ViT.
COCO average precision, exactly
Detection is scored by average precision, AP. Recall the ranking version from §0.11. Sort the predictions by score. At each cutoff, precision is the fraction of the flagged items that are correct, and recall is the fraction of all the positives that have been found. AP summarizes the resulting precision-recall curve in one number. In ranking, and in retrieval (§7.5), every item is relevant or not before you rank anything. In detection, whether a prediction is correct depends on which object it is matched to, on an IoU threshold, and on which other predictions got there first.
So COCO defines its own procedure, and the official evaluation code, pycocotools, is the only authority on it. Here it is step by step, because nearly every detection number in papers and in this section comes from it.
In plain words, rank all detections by confidence, walk down the list counting hits, and summarize the precision-recall curve by its upper envelope, sampled at evenly spaced recalls. Averaging over thresholds from 0.50 to 0.95 rewards boxes that are not only in the right place but tight.
You will still meet AP numbers computed under older rules, in papers and in interviews. The main ones come from the PASCAL VOC benchmark, which COCO replaced.
The cell reproduces the numbers at threshold 0.5, compares the three interpolation rules, and draws the curve with its envelope.
Python · cell 8
The three rules give 0.571, 0.564, and 0.567 on the same detections. Differences of this size are why papers state their protocol, and why the number from your own script may not match the leaderboard until you use pycocotools, COCO's official evaluation code.
The widget runs the whole procedure on a scene of five objects. It draws the precision-recall curve with its envelope at a chosen IoU threshold, and the AP at each of the ten thresholds that COCO averages.
How does a list of scored boxes become an AP number?
Five objects, solid, and the detections of one class, dashed. Click a detection to drop it or bring it back.
Loading interactive figure…
Interview
COCO average precision for one class
Write coco_ap(dets, gts, iou_thresholds=np.linspace(0.5, 0.95, 10), max_dets=100) and return the mean of APt over the thresholds. dets is a list of (image_id, [x1, y1, x2, y2], score) and gts a list of (image_id, [x1, y1, x2, y2], is_crowd), all for one class.
Follow the COCO definition above exactly. That means the cap of max_dets detections per image, and greedy matching in descending score order to the unmatched regular object of highest IoU, provided it is at least t. A crowd region is matched only when no regular object qualifies, with IoU equal to the intersection over the detection's area, and its matches are then ignored. Finish with the envelope and 101-point interpolation. Assume at least one regular object. The tests include the worked example, crowd regions, the cap, and random scenes checked against a reference that agrees with pycocotools.
import numpy as np
def coco_ap(dets, gts, iou_thresholds=np.linspace(0.5, 0.95, 10), max_dets=100):
"""dets: list of (image_id, [x1, y1, x2, y2], score). gts: list of (image_id, [x1, y1, x2, y2], is_crowd).
Return COCO AP for one class, averaged over the IoU thresholds."""
raise NotImplementedError
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Two properties of AP matter in practice. First, it measures ranking, not calibration. Multiply every score by 0.1 and AP does not move. A detector with excellent AP can still output scores that are useless as probabilities, so a deployed system that thresholds scores needs a separate calibration step (§0.11). Second, low-scoring detections are free. A false positive ranked below every true positive adds an operating point at the final recall with lower precision, which the envelope ignores, so AP does not change at all. That is why detectors submit up to 100 boxes per image even when an image holds three objects.
Segmentation heads
A semantic segmentation model must output a class for every pixel, at the input resolution, from features at stride 16 or 32. A 512 by 512 image at stride 16 gives a 32 by 32 grid, so the head must turn 1,024 vectors into 262,144 pixel labels. The oldest answer is the fully convolutional network (Long et al. 2015). It applies a 1×1 convolution to the last feature map as a classifier for each location. Then it upsamples the class scores back to full resolution with bilinear interpolation or transposed convolutions (§0.8). Skip connections add in scores from finer, earlier stages to sharpen the boundaries. For Transformers there are three standard designs.
Reassembling a plain ViT. DPT (Ranftl et al. 2021) reads the tokens of a plain ViT at four depths and reshapes each set back into a grid. It resamples the four grids to strides 4, 8, 16, and 32 with convolutions and transposed convolutions, and fuses them from coarse to fine. It is an FPN built from a ViT's layers rather than its stages.
An all-MLP decoder. SegFormer (Xie et al. 2021) pairs a hierarchical Transformer encoder with a decoder that projects each stage to a common width, upsamples all of them to stride 4, concatenates them, and classifies each pixel.
Mask classification. Instead of asking each pixel "which class are you", ask "which masks are there, and what class is each one". This is DETR's set prediction applied to masks.
Mask classification works as follows in MaskFormer (Cheng et al. 2021) and its successor Mask2Former (Cheng et al. 2022). A pixel decoder, an FPN-like module on the backbone, produces an embedding for every pixel of a stride-4 grid with H′ rows and W′ columns, stacked as F∈RH′W′×d. A Transformer decoder updates Nq queries, as in DETR. Each query j yields a class distribution p^j over K+1 classes and a mask embeddingej∈Rd. Its mask is the dot product of the mask embedding with every pixel's embedding,
Y^j=σ(Fej)∈[0,1]H′W′.
In plain words, a pixel belongs to query j's mask when its embedding points the same way as the query's mask embedding. Training uses Hungarian matching, as in DETR, with a mask cost in place of the box cost. That cost is a binary cross-entropy or focal term plus a dice term, both computed on 112×112=12,544 sampled points rather than on the whole mask, which cuts training memory by 3 times in Mask2Former.
Dice ignores the pixels that are correctly left out, which is the point. Take a 100-pixel image whose object covers 4 pixels, and a model that predicts probability 0.01 everywhere, an empty mask. Its per-pixel cross-entropy averages 0.19, which looks small because 96 of the 100 pixels are right. Its dice loss is 1−(2⋅0.04+1)/(1.0+4+1)=0.82, close to the maximum of 1. A small object cannot be drowned out by a large background.
One output format now serves all three segmentation tasks. For semantic segmentation, pixel u gets the class argmaxc∑jp^j(c)Y^j[u]. For instance segmentation, each query is a scored mask. For panoptic segmentation, drop the queries whose most likely class cj is no object or whose confidence is low, and give pixel u to the query argmaxjp^j(cj)Y^j[u].
Mask2Former's main change is in the cross-attention. A query that is meant to describe one object should not average features from the whole image. So Mask2Former restricts each query to the region its own current mask covers. It uses the additive attention mask of §4.4, which puts −∞ on the scores of the positions a query must not see, so their softmax weights are exactly 0.
Measuring segmentation, mIoU and panoptic quality
Semantic segmentation is scored per class, over pixels. A confusion matrix counts in entry nab, for a,b∈{1,…,K}, the pixels whose true class is a and predicted class is b, summed over the whole dataset. From it, TPc=ncc are the pixels correctly called c, FPc=∑anac−ncc the pixels wrongly called c, and FNc=∑bncb−ncc the pixels of class c that were missed. These are the counts of §0.11, with pixels as the examples.
mIoU is the IoU from the start of this section, applied to the set of pixels of one class. Every class gets the same weight in the mean, so a class with few pixels counts as much as the sky. It has two blind spots. It does not know about instances, so merging two touching cars into one blob costs nothing. And accumulating over the dataset, the standard, gives a different number from averaging per-image scores, which weights small images and rare classes differently.
Panoptic quality, PQ (Kirillov et al. 2019), scores the segments themselves rather than the pixels, so it does see instances. A predicted segment and a true segment of the same class are matched if their IoU is strictly greater than 0.5. That threshold makes the matching unique without any search.
Because each true segment has at most one match, three counts follow with no search at all. They are the matched pairs, the predicted segments left over, and the true segments left over, and PQ is built from exactly those three.
Core
mIoU from a confusion matrix
Write miou(pred, target, n_classes, ignore_index=255) for integer label arrays of the same shape, with any number of images stacked in front. Return (miou, iou), where iou has shape (n_classes,) and holds np.nan for classes absent from both the prediction and the target. Drop the pixels whose target is ignore_index, then accumulate one confusion matrix over all the remaining pixels.
import numpy as np
def miou(pred, target, n_classes, ignore_index=255):
"""pred, target: integer label arrays of the same shape, any number of images.
Return (mIoU, per-class IoU array with nan for classes absent from both)."""
pred, target = np.asarray(pred), np.asarray(target)
acc = float((pred == target).mean()) # placeholder, pixel accuracy
return acc, np.full(n_classes, acc)
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Promptable segmentation, from SAM to SAM 3
Every model so far was trained for a fixed list of classes. Kirillov et al. (2023) asked a different question, the vision version of prompting a language model. Can one model segment anything a user points at, in any image, without being told its class? Their answer is SAM, the Segment Anything Model, now the standard tool for labeling masks and for interactive cut-outs.
The ambiguity clause matters. A click on a person's shirt could mean the shirt or the person, and both answers are correct. A model trained with one output and an ordinary loss learns to output the average of the plausible masks, which is no mask at all. SAM's design follows from two requirements, a real-time response to each prompt and an honest handling of ambiguity. It has three parts.
Image encoder. The encoder is a ViT-H/16 (the encoder of §27.2, huge size, 16-pixel patches), pretrained without labels by masked autoencoding, which hides most patches and learns to reconstruct them. It reads the image resized so its longer side is 1024 and padded to 1024×1024, a 64×64 grid of 4,096 tokens. Global attention over 4,096 tokens in all 32 blocks would be expensive. So 28 blocks attend only within 14×14 windows of tokens and four equally spaced blocks attend globally, the design that §27.5 described for plain-ViT detectors. Two convolutions then give a 64×64×256 image embedding, computed once per image.
Prompt encoder. Each point becomes a 256-dimensional vector, a positional encoding of its location plus a learned embedding that says foreground or background. A box becomes two such vectors, one per corner. A mask prompt is downsampled by small convolutions and added to the image embedding.
Mask decoder. The decoder adds a few learned output tokens to the prompt vectors. An output token is a learned vector, like the class token of §27.1, whose final state becomes one predicted mask. All these tokens go through a two-layer Transformer of width 256 with 8 heads. Each layer does four things. The tokens attend to each other. The tokens cross-attend to the 4,096 image vectors. An MLP updates the tokens. And the image vectors cross-attend back to the tokens. That last step updates the image embedding with the prompt, which is why the design is called two-way. Each mask is then the dot product of an output token's vector with every pixel of an upsampled image embedding, the same mask-as-dot-product idea as Mask2Former.
Ambiguity. For a single ambiguous prompt, the decoder outputs three masks, typically the whole object, a part, and a sub-part, plus a predicted IoU for each. Training computes the loss against every one of the three and back-propagates only the smallest. Each output is then free to specialize in one interpretation instead of averaging them. When several prompts are given, ambiguity is rare, and a fourth output token produces a single mask.
The split between a heavy encoder and a light decoder is an amortization argument. The expensive part runs once and is shared by many cheap requests. It is worth checking the size of the gap yourself. The cell counts multiply-adds for SAM's ViT-H encoder at 1024 pixels, with the 4,096-token grid padded to 70×70 so that it tiles into 25 windows of 14×14. Then it makes a rough count for the decoder.
Python · cell 9
The encoder costs about 2.8 trillion multiply-adds and the decoder about 1.8 billion, a ratio near 1,600. Windowing saves 1.1 trillion multiply-adds per image compared with all-global attention, by the cost formula of §27.2. The encoder runs once on a GPU when the image is loaded. Every click afterward costs only the decoder, which is why SAM feels instant in a browser. Interviewers like this question because the answer is a design principle, put the expensive computation where it can be shared.
In code, the split is visible in the API. The predictor below is from the released segment_anything package (shown, not run).
Research
SAM's minimum-over-masks loss and IoU targets
Write sam_mask_loss(pred_logits, gt_mask, focal_w=20.0, dice_w=1.0, alpha=0.25, gamma=2.0). pred_logits has shape (3, H, W), three candidate masks as logits, and gt_mask is a binary (H, W) array. For each candidate, compute two losses. The first is the sigmoid focal loss averaged over pixels, with αt equal to alpha on foreground pixels and 1 - alpha on background pixels. The second is the dice loss on probabilities, with smoothing 1. Combine them as focal_w * focal + dice_w * dice, and return (loss, k), the smallest combined loss and the index of the mask that achieves it. Use a numerically stable log-sigmoid.
Also write iou_target(pred_logits, gt_mask), which returns the (3,) IoU of each mask, thresholded at logit 0, with the ground truth. When a mask and the ground truth are both empty, the prediction is perfect, so return 1. This is the target SAM's IoU head regresses toward.
import numpy as np
def sam_mask_loss(pred_logits, gt_mask, focal_w=20.0, dice_w=1.0, alpha=0.25, gamma=2.0):
"""pred_logits (3, H, W), gt_mask (H, W) of 0 and 1. Return (min combined loss, index of that mask)."""
raise NotImplementedError
def iou_target(pred_logits, gt_mask):
"""Return the (3,) IoU of each thresholded mask (logit > 0) with gt_mask."""
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
SAM 2, memory for video
A video is a sequence of frames in which the object you clicked keeps moving, gets hidden, and comes back. Running SAM frame by frame would need a new prompt on every frame. SAM 2 (Ravi et al. 2024) turns the model into a streaming one that remembers the object.
Each frame passes once through an image encoder. SAM 2 uses Hiera (Ryali et al. 2023), a hierarchical ViT pretrained with MAE and described in §27.5. Its finer stages also feed the mask decoder directly, to sharpen mask edges. Before decoding, a memory attention module of 4 Transformer blocks lets the current frame's features attend to a memory bank of earlier frames.
The memory bank holds memories of recent frames and of every frame the user prompted, each built from the frame's features and its predicted mask. A new head predicts whether the object is visible at all in the current frame, since in video it may be fully hidden. The prompt encoder and decoder are SAM's.
Here is the loop on a concrete clip. You click a dog in frame 1. In frames 2 to 39 the memory of frame 1 and of the latest frames lets the model find the dog without a new click. In frame 40 the dog walks behind a tree, and the visibility head says the object is absent, so no mask is drawn. In frame 55 the dog reappears, and the kept memory of the prompted frame lets the model pick it up again. If it picks the wrong dog, one corrective click on that frame becomes a new prompted memory.
As with SAM, a data engine with the model in the loop built the training set. SA-V has 50.9K videos with 642.6K masklets (an object's masks across time), 35.5M masks in total. On video segmentation, SAM 2 is more accurate than earlier methods while needing 3 times fewer interactions. On images it is more accurate than SAM and 6 times faster, mostly because the Hiera encoder is smaller and more efficient than ViT-H.
From a fixed class list to text queries
Every detector so far ends in a K-way classifier, one learned weight vector per class. So it can find only the K classes it was trained on, and adding "forklift" means labeling new data and retraining. The fix comes from CLIP, which trains an image encoder and a text encoder so that a picture and its caption land near each other. CLIP's zero-shot classifier embeds each class name with the text encoder and picks the class whose embedding is closest to the image's. Do the same for regions instead of whole images. Replace the class weight vectors by text embeddings of the class names, and the list of classes becomes an input.
In plain words, a region is labeled with whichever phrase its embedding points toward, and the phrases can be anything the text encoder can read. A sigmoid per phrase, rather than a softmax over phrases, lets one region match "dog" and "terrier" at once, and lets an image contain none of the queried phrases. The bias matters because most region-phrase pairs are negatives, the same imbalance as in focal loss.
The simplest instance is OWL-ViT (Minderer et al. 2022). It takes a ViT image-text model pretrained like CLIP and removes the final pooling. To every output patch token it attaches a linear projection that gives ei and a small MLP that gives a box. So every patch token, at least 576 of them, is a candidate object, and there is no decoder. It is fine-tuned on detection data with DETR's matching loss. Its ViT-L/14 reaches 34.6 AP on LVIS, a dataset with over a thousand categories. On LVIS's rare categories, which were removed from its detection training data, it reaches 31.2 AP.
A second family pretrains on phrase grounding, the task of finding the region that each phrase of a sentence describes, and fuses the text into the image features. The main examples are GLIP (Li et al. 2022c) and Grounding DINO (Liu et al. 2023), whose largest model reaches 52.5 AP on COCO with no COCO training data.
Read such "zero-shot COCO" numbers with care. Objects365, a large detection dataset in their training data, nearly covers COCO's 80 categories. So the test is new images, not new concepts, and the rare categories of LVIS are the harder test.
SAM 3, prompting with concepts
SAM and SAM 2 segment the one object you point at. Ask for "every yellow school bus" and they cannot help, because they have no notion of a category. SAM 3 (Carion et al. 2025) defines promptable concept segmentation. Given a short noun phrase ("striped cat"), image exemplars (boxes on examples, positive or negative), or both, it detects, segments, and tracks every instance of the concept in an image or a video.
In terms of the previous subsection, SAM 3 is an open-vocabulary detector built like DETR. It also accepts exemplar boxes as prompts, and it adds masks, a presence token, and tracking. Its architecture brings this whole section together. A shared backbone, the Perception Encoder (Bolya et al. 2025), is trained to align images with text as CLIP does, and it encodes both the image and the phrase. A fusion encoder lets the image features cross-attend to the prompt tokens. Then a DETR-style decoder of learned object queries predicts, for each query, whether it is a match and its box. Each box is refined layer by layer, as in DETR's descendants above, and a mask head dots query embeddings with pixel embeddings, as in Mask2Former.
The new piece is a learned global presence token, which predicts only whether the concept appears in the image at all. Each query then solves only localization, and its final score is a product,
p(query i is a match)=p(concept present in the image)⋅p(query i matches∣concept present).
In plain words, deciding "is there a forklift in this picture" needs global context, while drawing a box needs local detail. Asking every query to do both at once makes the two objectives fight, and factoring the score separates recognition from localization. For video, a tracker in the style of SAM 2 propagates each detected instance with memory.
How text-aligned image features are trained is the subject of CLIP's contrastive training, and how the wording of a class prompt changes zero-shot accuracy is taken up with zero-shot classification. Finding the moment in a video that a phrase describes is taken up with video-language models. Robots use such masks too, taking the outline of the object to grasp from a SAM-style model instead of learning segmentation from scratch, a pattern that recurs in robot learning.
Choosing among the families
Family
Examples
Output and post-processing
Strengths
Weaknesses
Two-stage, anchor-based
Faster R-CNN, Mask R-CNN, Cascade R-CNN
RPN proposals, then RoIAlign features and per-region class, box, and mask; NMS
Mature, accurate on small objects, easy to add heads
Many hand-set hyperparameters, NMS, slower
One-stage, dense
RetinaNet, FCOS, CenterNet, YOLO family
A prediction at every location, from anchors or as distances to the sides; NMS
Fast, simple deployment
Duplicates handled only by NMS, crowds suffer, results depend on the label assignment rule
Set prediction
DETR, Deformable DETR, DINO, RT-DETR, RF-DETR
A fixed set of queries; no NMS
End to end, the strongest published accuracy, and the best real-time results since RT-DETR
Matching makes training slower and less stable, needs the fixes above
Mask classification
MaskFormer, Mask2Former
Query masks plus classes, one model for three segmentation tasks
Unifies semantic, instance, panoptic
Heavy pixel decoder, fixed class list
Open-vocabulary
OWL-ViT, GLIP, Grounding DINO, YOLO-World
Region or query embeddings scored against text embeddings of any phrase list
New classes without retraining, and they pre-label data for everything else
Below a closed-set detector trained on the target classes, and zero-shot numbers often share concepts with the training data
Promptable
SAM, SAM 2, SAM 3
Masks for a click, box, phrase, or exemplar
Zero-shot, interactive, labels data for everything else
SAM and SAM 2 have no semantics; quality is bounded by the prompt
A useful default in 2026, for a new detection or segmentation problem with modest labeled data, is a DETR-family detector or a Mask2Former-style head on a strong self-supervised ViT backbone, with SAM 2 or SAM 3 in the labeling loop to produce the training masks.
Lin et al. (2017b). Focal Loss for Dense Object Detection. RetinaNet and focal loss, with the clearest account of why class imbalance hurts one-stage detectors.
He et al. (2017). Mask R-CNN. The mask branch, RoIAlign, and the ablations of Table 2 that show why alignment matters, the clearest account of two-stage detection.
Carion et al. (2025). SAM 3: Segment Anything with Concepts. Promptable concept segmentation, the presence token, and the data engine with AI verifiers.
Watch next
🎬 Lecture 15: Object Detection · Michigan OnlineJustin Johnson's lecture on detection from scratch, including IoU, NMS, mAP, anchors, and the R-CNN family, at the pace of a university course.🎬 Lecture 16: Detection and Segmentation · Michigan OnlineThe follow-up lecture covering semantic, instance, and panoptic segmentation, Mask R-CNN, and FPN-style multi-scale features.🎬 DETR: End-to-End Object Detection with Transformers (Paper Explained) · Yannic KilcherA careful walk through DETR's object queries, bipartite matching loss, and why it needs no NMS.🎬 Segment Anything - Model explanation with code · Umar JamilSAM's image encoder, prompt encoder, and two-way mask decoder explained alongside the released code.