Paper · 2022-12-14 · cs.CV
RTMDet: An Empirical Study of Designing Real-Time Object Detectors
RTMDet is a family of real-time one-stage detectors (tiny to extra-large). It uses CSPNeXt blocks with 5x5 depthwise convolutions, fewer but wider blocks, and a dynamic label assignment with IoU soft labels, trained with cached Mosaic/MixUp. Author-reported: 52.8 AP on COCO val2017 for RTMDet-x at 3.10 ms (FP16, NVIDIA 3090, TensorRT), with instance and rotated variants.
Object detectionLabel assignmentEfficient vision backbonesData augmentationobject-detectionreal-timelarge-kernellabel-assignmentinstance-segmentationrotated-object-detection
arXivPDFCodeMarkdown17 min read
AI-compiled by claude-haiku-5-5 on 2026-10-24, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Object detectors find things in pictures and draw boxes around them. Self-driving cars, robots and drones need this to run fast, so the detector has to be both accurate and quick. This paper is a set of experiments that puts together a detector family, called RTMDet, aimed at that goal, and reports what helped.
The main changes are in three places. The building blocks inside the network use a larger filter (5 by 5 instead of 3 by 3) that sees more of the image at once. The network is made shallower, with fewer blocks and wider channels, so it runs faster on a GPU. Finally, during training, the rule that decides which predicted box should learn from which object is made softer: a box that overlaps the object well gets a stronger signal, instead of a plain yes or no. Training also reuses already-loaded images when it mixes them together, which saves time while loading data.
The same detector is then adapted to outline object shapes instead of drawing boxes, and to handle boxes that are tilted. The adaptations are small changes to the output part of the network. The authors report that the family has a good balance between accuracy and speed, and that it reaches new results on those two tasks. All numbers are the authors' own.
TL;DR
RTMDet is a family of one-stage object detectors built around CSPNeXt blocks with 5x5 depthwise convolutions, reduced block depth with wider channels, and a shared detection head §3.1 §3.2. Training uses a dynamic soft label assignment whose matching cost takes the IoU as a soft target, plus cached Mosaic and MixUp and a two-stage schedule §3.3. Author-reported: RTMDet-x reaches 52.8 AP on COCO val2017 at 3.10 ms per image (FP16, TensorRT, batch 1, NVIDIA 3090, NMS excluded) tab. 2 §4.2. Tiny to x models are provided, and the same network is extended to instance segmentation and rotated boxes §3.4.
Problem
Real-time detectors in the YOLO line were improved by better architectures and training recipes, but the authors argue that the design space of their components has not been studied systematically §1. Two specific costs are named. Large receptive fields help dense prediction, yet earlier ways of getting them (dilated convolutions, non-local blocks) are too expensive for real-time use §3.2. Re-parameterised 3x3 convolutions speed up inference but slow training, raise training memory and widen the quantisation error gap §3.2. In the training recipe, dynamic label assignment costs built from binary labels can prefer a box with a high class score and a poor location, and strong mixing augmentations produce samples that are "noisy" §3.3.
The paper assumes 2D object detection with standard COCO-style training (118K training images, 5K validation images) §4.1. Rotated detection is evaluated on DOTA, whose images are cropped into 1024x1024 patches §4.1.
Method
Paths in this section are relative to mmdet/models/ in the official code.
Short names: assigner = task_modules/assigners/dynamic_soft_label_assigner.py,
head = dense_heads/rtmdet_head.py, csp = layers/csp_layer.py,
backbone = backbones/cspnext.py.
Macro architecture. RTMDet is a one-stage detector with a backbone, a neck that fuses multi-scale features with top-down and bottom-up paths, and a head that predicts a box and class at each location of each scale §3.1 fig. 2. The backbone and neck use CSP-style blocks. The head predicts classes and boxes for each scale; for instance segmentation, extra heads predict kernels and mask features fig. 2.
Basic building block. The authors replace the 3x3 convolution of a CSPDarkNet block with a 5x5 depthwise convolution, which they say enlarges the effective receptive field at low cost §3.2 fig. 3 (b). Ablation: 3x3 gives 50.0 AP at 2.10 ms, 5x5 gives 50.9 AP at 2.11 ms, and 7x7 gives 51.1 AP at 2.73 ms, with the 3x3 plus 5x5 combination chosen as the best speed-accuracy trade-off tab. 5 §4.3.
The block used in code has a 3x3 convolution, then a depthwise-separable
convolution with a 5x5 kernel, with an identity shortcut when the shapes match
[code: csp.py#L82-L139]. Each CSP layer can add a channel-attention module
on its concatenated features [code: csp.py#L232-L233, csp.py#L244-L245].
Depth and width balance. The 5x5 depthwise plus point-wise pair adds
layers, which slows parallel inference. The authors therefore use fewer blocks
per stage and wider channels §3.2. Stage block counts are 3, 6, 6, 3 for the
base (large) model [code: backbone.py#L56-L62, backbone.py#L135]. Reducing
the second and third stages from 9 to 6 blocks cut latency by about 20% and
cost 0.5 AP; adding channel attention recovered 0.4 AP, at 2.40 ms against
2.11 ms for the 3-6-6-3 model without it tab. 5 §4.3.
Backbone and neck balance. Instead of growing the backbone, the authors give the neck blocks a larger expansion ratio so that backbone and neck have similar capacity §3.2. In the ablation this gives similar accuracy at lower latency than the alternative split (63% backbone, 29% neck) tab. 5 §4.3.
Shared detection head. Heads share convolution weights across scales, but
each scale has its own batch-normalisation layers. The authors say BN is cheaper
than group normalisation at inference because it uses statistics computed
during training §3.2. Ablation: a shared head with BN statistics gives 48.0 AP,
a fully separate head 51.2 AP with 57.03M parameters, and the shared head with
separate BN 51.3 AP with 52.32M parameters tab. 5 §4.3.
In code, only the conv modules are shared across levels; each level keeps its
own BN, and the classification and regression branches are separate
[code: head.py#L629-L633].
Dynamic soft label assignment. Each training prior is matched to ground truth using a cost, and the number of positives per gt is chosen dynamically, following SimOTA §3.3. The cost is
C = \lambda_1 C_{cls} + \lambda_2 C_{reg} + \lambda_3 C_{center} eq. 1
with \lambda_1 = 1, \lambda_2 = 3, \lambda_3 = 1 §3.3 eq. 1.
The classification cost uses the IoU between prediction and gt as a soft label, inspired by GFL §3.3:
C_{cls} = CE(P, Y_{soft}) \times (Y_{soft} - P)^2 eq. 2
The regression cost uses the negative logarithm of IoU instead of GIoU, so that matches with low IoU are penalised more strongly §3.3:
C_{reg} = -\log(IoU) eq. 3
The centre cost is a soft prior, not a fixed centre region. The authors set \alpha = 10 and \beta = 3 §3.3:
C_{center} = \alpha^{\left| x_{pred} - x_{gt} \right| - \beta} eq. 4
# Dynamic soft label assignment, one image [§3.3] [eq. 1-4]
# priors (N, 2), strides (N,); boxes (N, 4) decoded; logits (N, C)
# gt_boxes (G, 4); gt_labels (G,)
def assign(priors, strides, boxes, logits, gt_boxes, gt_labels):
# Candidates: priors whose centre lies inside some gt box
# Not stated in the paper [code: assigner#L116-L127]
candidates = inside_any_box(priors, gt_boxes)
# IoU between candidate boxes and gts [§3.3]
# [code: assigner#L154]
ious = pairwise_iou(boxes[candidates], gt_boxes) # (K, G)
# Soft classification cost against the IoU target [eq. 2]
# [code: assigner#L157-L168]
soft_target = one_hot(gt_labels) * ious[..., None] # (K, G, C)
cls_cost = bce_with_logits(logits[candidates], soft_target)
cls_cost = cls_cost * (soft_target - sigmoid(logits[candidates])) ** 2
cls_cost = cls_cost.sum(dim=-1) # (K, G)
# Log-IoU regression cost, weight 3 [eq. 3]
# [code: assigner#L155]
reg_cost = -3.0 * log(ious + 1e-7)
# Soft centre cost, distance divided by stride [eq. 4]
# [code: assigner#L150-L152]
distance = norm(priors - gt_centres) / strides
centre_cost = 10.0 ** (distance - 3.0)
# Total cost, weights 1, 3 and 1 [eq. 1] [code: assigner#L170]
cost = cls_cost + reg_cost + centre_cost
# Dynamic k per gt: sum of its 13 largest IoUs, truncated, min 1
# [code: assigner#L203-L206]
dynamic_k = max(1, int(sum(top13_ious(ious))))
# Each gt takes its dynamic_k cheapest candidates [code: assigner#L207]
matches = take_cheapest(cost, dynamic_k)
# A prior claimed by several gts keeps only the cheapest gt
# [code: assigner#L214-L219]
matches = keep_cheapest_gt(matches, cost)
# The matched IoU is the classification target and the regression
# loss weight [code: head#L475-L476]
return matches, matched_iou(matches, ious)Cached Mosaic and MixUp. Mosaic and MixUp need several images per sample,
which costs data loading time and can produce unrealistic samples §3.3. The
authors keep a cache of already-loaded images and draw from it. A large cache
with random eviction behaves like the uncached operations; a small cache with
first-in-first-out eviction behaves like repeated augmentation, so the same
image can appear with different augmentations in one batch §3.3. Speed:
cached Mosaic takes 24.0 ms per 100 images against 87.1 ms uncached, and cached
MixUp takes 12.4 ms against 19.3 ms tab. 7 §4.4. Implementation:
transforms.py#L3344-L3420 (CachedMosaic, default cache 40, random pop) and
transforms.py#L3579-L3660 (CachedMixUp, default cache 20, random pop)
[code: transforms.py#L3416-L3417, transforms.py#L3657-L3658].
Two-stage training. The first stage (280 epochs) uses cached Mosaic and
MixUp; the authors drop rotation and shear (used by YOLOX) because they break
box alignment, and mix more images per sample instead §3.3 §4.4. The last
20 epochs use large-scale jittering, a fine-tuning stage close to the real
data distribution §3.3 tab. 1. The stage switch is at epoch 280 in the
code [code: rtmdet_l_8xb32-300e_coco.py#L177].
Optimisation. AdamW with weight decay 0.05 is used because SGD converged unstably under heavy augmentation; a flat-then-cosine learning rate and no decay on normalisation layers and biases each add accuracy §4.4 tab. 8. A pre-trained backbone with the RSB recipe adds a further 0.3 AP tab. 9 §4.5.
Instance segmentation (RTMDet-Ins). A CondInst-style branch is added: a mask feature head of 4 convolutions producing 8-channel features, and a kernel head predicting a 169-dimensional vector per instance that is split into three dynamic convolution kernels (88, 72 and 9 values) §3.4 fig. 4. The region prior uses the mask's centre of mass rather than the box centre, and the mask loss is dice loss §3.4. Not inspected in the code (see Paper vs code).
Rotated detection (RTMDet-R). Three changes: a 1x1 convolution predicts the angle, the box coder supports rotated boxes, and the GIoU loss is replaced by a rotated-IoU loss §3.4. COCO-pretrained weights can initialise the rotated model §3.4. Not inspected in the code (see Paper vs code).
Hyperparameters
Object detection and instance segmentation, 8 NVIDIA A100 GPUs §4.1.
| Name | Value | Where | Notes |
|---|---|---|---|
| Optimiser | AdamW | tab. 1 §3.3 [code: rtmdet_l_8xb32-300e_coco.py#L139] | config sets no betas |
| Base learning rate | 0.004 | tab. 1 [code: rtmdet_l_8xb32-300e_coco.py#L124] | |
| Weight decay | 0.05; 0 for bias and norm layers | tab. 1 §4.4 [code: rtmdet_l_8xb32-300e_coco.py#L139-L141] | |
| Optimizer momentum | 0.9 | tab. 1 | listed for AdamW but the code sets no betas; paper does not say which beta it means |
| Batch size | 256 (8 GPUs x 32) | tab. 1 [code: rtmdet_l_8xb32-300e_coco.py#L113] | |
| Epochs | 300 | tab. 1 §4.1 [code: rtmdet_l_8xb32-300e_coco.py#L122] | |
| Warm-up | 1000 iterations, linear | tab. 1 [code: rtmdet_l_8xb32-300e_coco.py#L145-L149] | start factor 1e-5 in code; not stated in paper |
| Learning-rate schedule | Constant to epoch 150, then cosine to 0.05 x base | §4.4 [code: rtmdet_l_8xb32-300e_coco.py#L152-L158] | "flat-cosine"; the final value 0.05 x base is not stated in paper |
| Input size | 640 x 640 | tab. 1 | |
| Stage 1 augmentation (epochs 1-280) | cached Mosaic and MixUp; HSV colour jitter; random flip | tab. 1 §3.3 [code: rtmdet_l_8xb32-300e_coco.py#L67-L81] | HSV jitter is not mentioned in the paper |
| Stage 1 resize ratio | (0.5, 2.0) for tiny and s; (0.1, 2.0) for m, l, x | §4.4 [code: rtmdet_tiny_8xb32-300e_coco.py#L26] [code: rtmdet_l_8xb32-300e_coco.py#L71] | |
| Stage 2 augmentation (last 20 epochs) | random resize, random crop 640, HSV, flip | tab. 1 [code: rtmdet_l_8xb32-300e_coco.py#L89-L95] | the paper names large-scale jittering; the code uses resize-and-crop |
| Mixed images per sample (stage 1) | "8" | §3.3 §4.4 | no value of 8 found in the configs |
| Cache, Mosaic / MixUp | large (40 / 20, random pop) for s, l, m, x; tiny: 20 / 10, FIFO | [code: rtmdet_tiny_8xb32-300e_coco.py#L18-L22, #L33-L39] | the paper's small-cache FIFO variant is the tiny setting |
| Soft cls cost, IoU as target | yes | eq. 2 [code: assigner#L163] | |
| Regression cost weight | 3 (log IoU) | eq. 3 §3.3 [code: assigner#L155] | |
| Centre cost weight | 1, alpha = 10, beta = 3 | eq. 4 §3.3 [code: assigner#L152, assigner#L56] | distance is divided by stride in code |
| Top-k for dynamic k | 13 | [code: rtmdet_l_8xb32-300e_coco.py#L52] [code: assigner#L57] | not stated in paper |
| EMA | ExpMomentumEMA, momentum 0.0002 | tab. 1 (decay 0.9998) [code: rtmdet_l_8xb32-300e_coco.py#L170-L173] [code: ema.py#L39-L40] | momentum ramps down from a higher value with gamma 2000 (code default) |
| Head | 2 stacked 3x3 convs, 1x1 predictions, SiLU, SyncBN, shared conv across scales | §3.2 [code: rtmdet_l_8xb32-300e_coco.py#L3-L48] [code: head.py#L629-L633] | |
| Regression output | exp on or off: on for l, m, x; off for tiny and s | [code: rtmdet_l_8xb32-300e_coco.py#L46] [code: head.py#L686-L689] | not stated in paper |
| Classification loss | QualityFocalLoss, beta 2.0 | [code: rtmdet_l_8xb32-300e_coco.py#L39-L43] | the ablation text says FocalLoss |
| Box loss | GIoU, weight 2.0 | [code: rtmdet_l_8xb32-300e_coco.py#L44] | |
| Test: score threshold | 0.001 before NMS | §4.1 [code: rtmdet_l_8xb32-300e_coco.py#L59] | ablations use 0.05 and 100 kept boxes §4.1 |
| Test: pre-NMS top | 30000 | [code: rtmdet_l_8xb32-300e_coco.py#L57] | not stated in paper |
| Test: NMS IoU | 0.65 | [code: rtmdet_l_8xb32-300e_coco.py#L60] | not stated in paper |
| Test: max detections | 300 | §4.1 [code: rtmdet_l_8xb32-300e_coco.py#L61] | |
| Model scale (deepen / widen / neck channels / neck blocks) | tiny 0.167 / 0.375 / 96 / 1; s 0.33 / 0.5 / 128 / 1; m 0.67 / 0.75 / 192 / 2; l 1 / 1 / 256 / 3; x 1.33 / 1.25 / 320 / 4 | [code: rtmdet_tiny_8xb32-300e_coco.py#L7-L12] [code: rtmdet_s_8xb32-300e_coco.py#L5-L10] [code: rtmdet_m_8xb32-300e_coco.py#L3-L6] [code: rtmdet_x_8xb32-300e_coco.py#L3-L7] | scale factors are not in the paper; the paper gives only the resulting sizes |
| Rotated (RTMDet-R) | lr 0.00025; batch 8; 36 epochs; 1024 input; random flip and rotate | tab. 1 | taken from the paper; the code is in MMRotate, not checked |
| DOTA crop | 1024 patches; overlap 256 (single scale) or 500 (multi scale, scales 0.5, 1.0, 1.5) | §4.1 | not checked in code |
| Latency measurement | FP16, TensorRT 8.4.3, cuDNN 8.2.0, batch 1, NVIDIA 3090; NMS excluded for detection, included for instance segmentation | §4.1 tab. 3 | the benchmark pipeline is not in the repository |
Results
Author-reported, COCO val2017, models trained 300 epochs without extra data or distillation tab. 2. Latency as in the Hyperparameters table. Full table from the paper (rows in source order):
| Model | Input | Params (M) | FLOPs (G) | Latency (ms) | AP (%) | AP50 (%) |
|---|---|---|---|---|---|---|
| YOLOv5-n | 640 (LB) | 1.9 | 2.3 | 1.51 | 28.0 | 45.7 |
| YOLOX-tiny | 416 x 416 | 5.1 | 3.3 | 0.82 | 32.8 | 50.3 |
| YOLOv6-n | 640 (LB) | 4.3 | 5.6 | 0.79 | 35.9 | 51.2 |
| YOLOv6-tiny | 640 (LB) | 9.7 | 12.5 | 0.86 | 40.3 | 56.6 |
| RTMDet-tiny | 640 x 640 | 4.8 | 8.1 | 0.98 | 41.1 | 57.9 |
| YOLOv5-s | 640 (LB) | 7.2 | 8.3 | 1.63 | 37.4 | 56.8 |
| YOLOX-s | 640 x 640 | 9.0 | 13.4 | 1.20 | 40.5 | 59.3 |
| YOLOv6-s | 640 (LB) | 17.2 | 22.1 | 0.92 | 43.5 | 60.4 |
| PPYOLOE-s | 640 x 640 | 7.9 | 8.7 | 1.34 | 43.0 | 59.6 |
| RTMDet-s | 640 x 640 | 8.99 | 14.8 | 1.22 | 44.6 | 61.9 |
| YOLOv5-m | 640 (LB) | 21.2 | 24.5 | 1.89 | 45.4 | 64.1 |
| YOLOX-m | 640 x 640 | 25.3 | 36.9 | 1.68 | 46.9 | 65.6 |
| YOLOv6-m | 640 (LB) | 34.3 | 41.1 | 1.21 | 48.5 | - |
| PPYOLOE-m | 640 x 640 | 23.4 | 25.0 | 1.75 | 49.0 | 65.9 |
| RTMDet-m | 640 x 640 | 24.7 | 39.3 | 1.62 | 49.4 | 66.8 |
| YOLOv5-l | 640 (LB) | 46.5 | 54.6 | 2.46 | 49.0 | 67.3 |
| YOLOX-l | 640 x 640 | 54.2 | 77.8 | 2.19 | 49.7 | 68.0 |
| YOLOv6-l | 640 (LB) | 58.5 | 72.0 | 1.91 | 51.0 | - |
| YOLOv7 | 640 (LB) | 36.9 | 52.4 | 2.63 | 51.2 | - |
| PPYOLOE-l | 640 x 640 | 52.2 | 55.0 | 2.57 | 51.4 | 68.6 |
| RTMDet-l | 640 x 640 | 52.3 | 80.2 | 2.40 | 51.5 | 68.8 |
| YOLOv5-x | 640 (LB) | 86.7 | 102.9 | 2.92 | 50.7 | 68.9 |
| YOLOX-x | 640 x 640 | 99.1 | 141.0 | 2.98 | 51.1 | 69.4 |
| PPYOLOE-x | 640 x 640 | 98.4 | 103.3 | 3.07 | 52.3 | 69.5 |
| RTMDet-x | 640 x 640 | 94.9 | 141.7 | 3.10 | 52.8 | 70.4 |
Instance segmentation, COCO val2017 tab. 3. Box and mask AP; latency includes box NMS and top-100 mask post-processing.
| Model | Epochs | Params (M) | FLOPs (G) | Latency (ms) | Box AP | Mask AP |
|---|---|---|---|---|---|---|
| CondInst-R50-FPN (800-1333) | 36 | 33.9 | 240.8 | - | 42.6 | 38.2 |
| RTMDet-Ins-R50-FPN (800-1333) | 36 | 35.9 | 295.2 | - | 45.3 | 39.7 |
| RTMDet-Ins-tiny (640) | 300 | 5.6 | 11.8 | 1.70 | 40.5 | 35.4 |
| RTMDet-Ins-s (640) | 300 | 10.2 | 21.5 | 1.93 | 44.0 | 38.7 |
| RTMDet-Ins-m (640) | 300 | 27.6 | 54.1 | 2.69 | 48.8 | 42.1 |
| RTMDet-Ins-l (640) | 300 | 57.4 | 106.6 | 3.68 | 51.2 | 43.7 |
| RTMDet-Ins-x (640) | 300 | 102.7 | 182.7 | 5.31 | 52.4 | 44.6 |
Rotated detection, DOTA-v1.0 test, mAP tab. 4: RTMDet-R-m and RTMDet-R-l reach 78.24 and 78.85 at single scale, and 80.26 and 80.54 at multiple scales (ImageNet pre-training). With COCO pre-training and multi-scale testing, RTMDet-R-l reaches 81.33 tab. 4 §4.2. Speed on DOTA-style input at 1024 tab. A1: RTMDet-R-m 5.79 ms (24.67M), RTMDet-R-l 8.20 ms (52.27M).
Other results: DOTA-v1.5, RTMDet-R-l multi-scale 78.12 mAP, against ReDet 76.80 tab. A2. HRSC2016, RTMDet-R-tiny 90.60 mAP07 tab. A3.
Ablations (all COCO val2017 unless stated; single runs, no spreads reported).
Model architecture tab. 5:
| Study | Setting | Params | GFLOPs | Latency (ms) | AP |
|---|---|---|---|---|---|
| Kernel size | 3x3 / 5x5 / 7x7 | 50.80M / 50.92M / 51.10M | 79.61 / 79.70 / 80.34 | 2.10 / 2.11 / 2.73 | 50.0 / 50.9 / 51.1 |
| Blocks (large) | 3-9-9-3 / 3-6-6-3 / 3-6-6-3 with CA | 53.40M / 50.92M / 52.30M | 86.28 / 79.70 / 79.90 | 2.60 / 2.11 / 2.40 | 51.4 / 50.9 / 51.3 |
| Backbone / neck (small) | 47% / 45% / 63% / 29% | 8.54M / 9.01M | 15.76 / 15.85 | 1.21 / 1.37 | 43.9 / 43.7 |
| Backbone / neck (large) | 47% / 45% / 63% / 29% | 50.92M / 57.43M | 79.70 / 93.73 | 2.11 / 2.57 | 50.9 / 51.0 |
| Head | Shared / Totally separate / Separate BN | 52.32M / 57.03M / 52.32M | 80.23 (all) | 2.44 (all) | 48.0 / 51.2 / 51.3 |
Training strategy:
| Study | Setting | AP |
|---|---|---|
| Label assignment (ResNet-50, 1x) | baseline / + soft cls cost / + soft centre prior / + log-IoU cost | 39.9 / 40.3 / 40.8 / 41.3 |
| Other assignments (ResNet-50, 1x) | ATSS / PAA / OTA / TOOD (w/o T-head) / Ours | 39.2 / 40.4 / 40.7 / 40.7 / 41.3 |
| SimOTA vs ours (RTMDet-s) | SimOTA / Ours | 43.2 / 44.5 |
Data augmentation tab. 7:
| Model | Stage 1 | Stage 2 | AP |
|---|---|---|---|
| RTMDet-s | LSJ | LSJ | 42.3 |
| RTMDet-s | Mosaic and MixUp | Mosaic and MixUp | 41.9 |
| RTMDet-s | Cached Mosaic and MixUp | Cached Mosaic and MixUp | 41.9 |
| RTMDet-s | Cached Mosaic and MixUp | LSJ | 43.9 |
| RTMDet-s | Cached (small) Mosaic and MixUp | LSJ | 44.2 |
| RTMDet-l | LSJ | LSJ | 46.7 |
| RTMDet-l | Mosaic and MixUp | Mosaic and MixUp | 49.8 |
| RTMDet-l | Cached Mosaic and MixUp | Cached Mosaic and MixUp | 49.8 |
| RTMDet-l | Cached Mosaic and MixUp | LSJ | 51.3 |
| RTMDet-l | Cached (small) Mosaic and MixUp | LSJ | 51.1 |
With the YOLOX augmentation, RTMDet-s gets 42.9 and RTMDet-l 50.6; with the paper's augmentation, 44.2 and 51.3 tab. 7.
Optimisation, RTMDet-s tab. 8: SGD with cosine LR is unstable; AdamW with cosine 43.0; AdamW with flat-cosine 43.3; without norm and bias decay 44.2; with RSB pre-trained backbone 44.5.
Step by step from YOLOX-s tab. 9: 40.2 baseline (9.0M, 13.4G, 1.20 ms); AdamW and flat-cosine 40.6; new architecture 41.8 (10.07M, 14.8G, 1.22 ms); shared head 41.8 (8.89M); label assignment and loss 42.9; improved augmentation 44.2; RSB pre-trained backbone 44.5.
Paper vs code
Code: https://github.com/open-mmlab/mmdetection, linked from the paper's
abstract. The paper points to the 3.x branch; the clone is the default branch
at code_commit, which contains configs/rtmdet/. Licence Apache-2.0.
- Classification loss. The ablation text describes a focal loss §4.4;
the configs use QualityFocalLoss with beta 2.0 [code:
rtmdet_l_8xb32-300e_coco.py#L39-L43]. - Regression weighting and normalisation. The matched IoU is both the
classification target and the weight of the regression loss; both losses are
normalised by the summed IoU over the batch [code:
head.py#L199-L204,head.py#L282-L287,head.py#L475-L476]. The paper does not describe this. - Candidate priors. Only priors whose centre is inside some gt box are
candidates [code:
assigner#L116-L127]. The paper does not state this. - Centre cost. The code uses the Euclidean distance divided by the stride,
not a per-coordinate term [code:
assigner#L150-L152]. Eq. 4 is written with a single coordinate difference and no stride. - Dynamic k. Sum of the top-13 IoUs, truncated to an integer, minimum 1
[code:
assigner#L203-L206,rtmdet_l_8xb32-300e_coco.py#L52]. - Stage 1 mixing. The paper says 8 images are mixed per sample §3.3; the
configs use CachedMosaic (4 images) and CachedMixUp (2 images), and no "8"
appears [code:
rtmdet_l_8xb32-300e_coco.py#L67-L81]. - Small-model cache. The paper says a small FIFO cache helps tiny and small
models by about 0.5 AP §4.4. Only the tiny config uses FIFO with a small
cache; the s config uses the larger random-pop defaults [code:
rtmdet_s_8xb32-300e_coco.py#L15,#L26-L29;rtmdet_tiny_8xb32-300e_coco.py#L18-L22]. - Stage 2. The paper names large-scale jittering §3.3 tab. 1. The code
uses random resize, a 640 crop, HSV colour jitter and flip [code:
rtmdet_l_8xb32-300e_coco.py#L89-L95]. The HSV jitter is also used in stage 1. - Regression output. exp is applied to the regression output for l, m and
x, but not for tiny and s [code:
head.py#L686-L689,rtmdet_tiny_8xb32-300e_coco.py#L12,rtmdet_l_8xb32-300e_coco.py#L46]. - EMA. The paper gives decay 0.9998 tab. 1. The code uses momentum
0.0002 with a ramp that starts higher, with gamma 2000 [code:
ema.py#L39-L40,rtmdet_l_8xb32-300e_coco.py#L172]. The ramp matters early in training only. - Learning rate. Warm-up starts at 1e-5 of the base rate, and cosine decay
ends at 0.05 of the base rate [code:
rtmdet_l_8xb32-300e_coco.py#L147,#L154]. Neither value is in the paper. - Test settings. Score threshold 0.001 and top 300 match §4.1. The pre-NMS
top-30000 and NMS IoU 0.65 are not in the paper [code:
rtmdet_l_8xb32-300e_coco.py#L57-L61]. - Backbone. The stem is three convolutions; the P5 stages and block counts
match the paper's 3-6-6-3 ablation [code:
backbone.py#L56-L62,backbone.py#L104-L128,backbone.py#L135]. - Not checked. RTMDet-Ins (instance segmentation) configs and the rotated model. The rotated code lives in MMRotate (named in the paper §4.2); it was not cloned. The rotated hyperparameters in tab. 1 are the paper's only.
- Latency pipeline. The TensorRT benchmark code is not in the repository, so the latency numbers cannot be reproduced from it.
Pitfalls
- Final AP for RTMDet-s differs. The main table reports 44.6 tab. 2; the ablation runs end at 44.5 tab. 8 tab. 9. The paper does not explain this.
- Ablation evaluation is cheaper. The ablations use score threshold 0.05 and 100 kept boxes, which the authors say may cost about 0.3 AP §4.1. Do not compare ablation numbers with the main table directly.
- Latency claims. Latency is FP16 TensorRT, batch 1, on one GPU, with NMS excluded for detection but included for instance segmentation tab. 3 §4.1. Speed comparisons with other models depend on that setup.
- Text claims not matching the tables.
- "300+ FPS" for RTMDet-x matches 3.10 ms tab. 2 (about 322 FPS).
- "180 FPS" for RTMDet-Ins-x §1 does not match 5.31 ms in tab. 3 (about 188 FPS); the speed conditions differ.
- RTMDet-s has "half" the parameters and computation of YOLOv6-s §4.2: the table gives 8.99M vs 17.2M parameters, but 14.8G vs 22.1G FLOPs (about 67%).
- RTMDet-R-m is said to be 18.5% faster than PPYOLOE-R-l app. A.1; the table gives 5.79 vs 7.09 ms, which is 18.3% lower latency.
- DOTA-v1.5 pre-training is not in the table. tab. A2 has no pre-training column; the text says COCO pre-training is the default there app. A.1.
- Regression loss is IoU-weighted. Both the classification target and the box-loss weight are the matched IoU, and the loss is normalised by the summed IoU. An implementation that uses hard labels or unweighted boxes will not match the reported behaviour.
- Dynamic k is truncated. Using rounding or no minimum changes which priors are matched.
- Cost terms can be extreme. The centre cost is 10 to the power of (stride-normalised distance minus 3), so distant priors get very large costs. The log-IoU term uses a 1e-7 floor.
- Cache behaviour depends on size. Random eviction with a large cache is close to uncached augmentation; FIFO with a small cache repeats images within a batch. Pick per model size as in the configs.
Lineage
- Builds on: YOLO-series detectors and their training recipes, especially YOLOX and its SimOTA label assignment §1 §3.3; CSPNet-style blocks fig. 2; large-kernel depthwise convolutions such as ConvNeXt and RepLKNet §3.2; GFL for the IoU soft label §3.3; cached-data augmentation ideas from YOLOX-style Mosaic and MixUp §3.3.
- Compared against: YOLOv5, YOLOX, YOLOv6, YOLOv7 and PPYOLOE on detection tab. 2; CondInst, SparseInst, SOLOv2 and Cascade R-CNN on instance segmentation tab. 3; ATSS, PAA, OTA and TOOD for label assignment tab. 6; PPYOLOE-R and the rotated detectors in tab. 4.
- Superseded by: not known from this wiki.
Source and license
Adapted from “RTMDet: An Empirical Study of Designing Real-Time Object Detectors” by Chengqi Lyu, Wenwei Zhang, Haian Huang, Yue Zhou, Yudong Wang, Yanyi Liu, Shilong Zhang, Kai Chen (arXiv:2212.07784), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/open-mmlab/mmdetection at commit cfd5d3a985b0 (Apache-2.0). Any quoted code is shown under that license.