Skip to content

[Analysis] YOLO-Master Optimization Feasibility on Small-Object Detections: a stride-4 (P2) head, especially on EsMoE-N, hits +2.2% mAP on VisDrone with only a fraction of S-tier FLOPs #98

Description

@skywalker-lt

YOLO-Master's small-object accuracy gains come from ES-MoE compute allocation, however the detection head is remained the standard form: P3/P4/P5 (stride 8/16/32) — so for real tiny objects (< 8 px, ubiquitous in areo datasets like VisDrone) never land on the grid and remain unlearnable to an extent. Adding a P2/stride-4 head closes exactly this gap. The standout is EsMoE-N-P2: +3.1 mAP50 / +2.2 mAP50-95 on VisDrone compared against the baseline EsMoE-N in #81, at 2.8 M params / 12.2 GFLOPs, sitting far below every S-tier detector. This can be considered a strong enhancement to the ES-MoE; the two fix orthogonal bottlenecks and compound.

1. Observation

The paper is explicit that detection runs "across P3, P4, P5 prediction layers." The small-object improvements (+2.1% over YOLOv13-N on VisDrone) are attributed to ES-MoE: dynamically routing expert compute to densely-packed scenes for better feature allocation.

That is an effective compute-allocation fix, not a spatial-resolution fix. With a finest stride of 8, an object's grid footprint is footprint = object_px / stride. A 7 px object at 640 has footprint ≈ 0.9 cell on a P3. MoE cannot recover a target the head can't sample. VisDrone is dominated by exactly these targets. So the architecture contributed to significant improvments on small objects while leaving the tiny object resolution floor untouched — the precise gap a stride-4 (P2) head fills.

2. The change — P2 head added & backbone untouched

The P2 head is a pure neck/head extension: the FPN top-down path is carried one level further down to stride-4, the PAN bottom-up path is re-rooted at P2, and detect becomes 4-level (P2, P3, P4, and P5). No transformer is inserted at the stride-4 head on purpose — global attention on a 160×160 map (640 input) is prohibitive for a Nano model, and the backbone already carries A2C2f area-attention + MoE gating. Below is the v0.1-N-P2 config; EsMoE-N-P2 grafts the identical head onto the stock EsMoE-N backbone, with Detect hooking the ES-MoE P-level sources at layers [3, 6, 9, 12] instead of [2, 5, 8, 11].

# YOLO-Master-v0.1-N-P2
# Backbone UNCHANGED from v0.1-N; only the neck/head is extended.
# Heads: P2/4, P3/8, P4/16, P5/32  ->  Detect x4.
nc: 80 
scales:
  n: [0.50, 0.25, 1024]

backbone:
  - [-1, 1, Conv, [64, 3, 2]]                       # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]]                      # 1-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]               # 2-P2/4  (P2 feature source)
  - [-1, 1, Conv, [256, 3, 2]]                      # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]               # 4
  - [-1, 1, ModularRouterExpertMoE, [512, 4, 2]]    # 5-P3/8  (P3 feature source)
  - [-1, 1, Conv, [512, 3, 2]]                      # 6-P4/16
  - [-1, 4, A2C2f, [512, True, 4]]                  # 7
  - [-1, 1, ModularRouterExpertMoE, [512, 8, 2]]    # 8-P4/16 (P4 feature source)
  - [-1, 1, Conv, [1024, 3, 2]]                     # 9-P5/32
  - [-1, 4, A2C2f, [1024, True, 1]]                 # 10
  - [-1, 1, ModularRouterExpertMoE, [1024, 16, 2]]  # 11-P5/32 (P5 feature source)

head:
  # FPN
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]      # 12
  - [[-1, 8], 1, Concat, [1]]                       # 13 cat backbone P4
  - [-1, 2, C3k2, [512, True]]                      # 14 (P4 td)
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]      # 15
  - [[-1, 5], 1, Concat, [1]]                       # 16 cat backbone P3
  - [-1, 2, C3k2, [256, True]]                      # 17 (P3 td)
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]      # 18
  - [[-1, 2], 1, Concat, [1]]                       # 19 cat backbone P2
  - [-1, 2, C3k2, [128, True]]                      # 20 (P2/4-tiny) <- Detect P2
  # PAN
  - [-1, 1, Conv, [128, 3, 2]]                      # 21
  - [[-1, 17], 1, Concat, [1]]                      # 22 cat head P3
  - [-1, 2, C3k2, [256, True]]                      # 23 (P3/8-small) <- Detect P3
  - [-1, 1, Conv, [256, 3, 2]]                      # 24
  - [[-1, 14], 1, Concat, [1]]                      # 25 cat head P4
  - [-1, 2, C3k2, [512, True]]                      # 26 (P4/16-medium) <- Detect P4
  - [-1, 1, Conv, [512, 3, 2]]                      # 27
  - [[-1, 11], 1, Concat, [1]]                      # 28 cat backbone P5
  - [-1, 2, C3k2, [512, True]]                      # 29 (P5/32-large)  <- Detect P5
  - [[20, 23, 26, 29], 1, Detect, [nc]]             # Detect(P2, P3, P4, P5)

3. Result — EsMoE-N-P2 (the standout)

All VisDrone, imgsz 640, 300 epochs, dense eval (--no-sparse-eval) for EsMoE models:

Model Params GFLOPs@640 mAP50 mAP50-95 W&B Runs
EsMoE-N (baseline) 2.69 M 8.8 0.350 0.203 View
EsMoE-N-P2 2.81 M (+4.4%) 12.2 0.381 (+0.031) 0.225 (+0.022) View
v0.1-N (baseline) 7.52 M 9.9 0.344 0.201 View
v0.1-N-P2 7.67 M 14.7 0.369 (+0.025) 0.218 (+0.017) View

Class-wise comparison:

Class Size v0.1-N v0.1-N-P2 Δ EsMoE-N EsMoE-N-P2 Δ
people tiny 0.106 0.136 +0.030 0.101 0.143 +0.042
pedestrian tiny 0.160 0.198 +0.038 0.165 0.203 +0.038
motor tiny/small 0.164 0.190 +0.026 0.166 0.200 +0.034
car small 0.533 0.566 +0.033 0.538 0.572 +0.033
bus medium 0.329 0.346 +0.017 0.351 0.378 +0.027
bicycle tiny/small 0.038 0.047 +0.009 0.036 0.059 +0.022
awning-tricycle tiny/small 0.091 0.092 +0.001 0.073 0.093 +0.021
van small 0.278 0.293 +0.015 0.278 0.296 +0.018
tricycle tiny/small 0.117 0.131 +0.014 0.122 0.136 +0.014
truck medium/large 0.198 0.191 −0.007 0.205 0.184 −0.021

Visualization:

Es-MoE-N-P2 vs EsMoE-N Image
v0.1-N-P2 vs v0.1-N Image

Two results:

  • The dense v0.1-N A/B (matched 640/300 epochs): +2.5 mAP50 / +1.7 mAP50-95 for +41% FLOPs. The per-class Δ is the textbook finer-head fingerprint — gains concentrate on the small classes (pedestrian +0.038, car +0.033, people +0.042, motor +0.034) and the largest class falls back slightly (truck −0.021).
  • EsMoE-N-P2 dominates v0.1-N-P2 on every axis at ~1/3 the params: higher mAP50 (0.381 vs 0.369), higher mAP50-95 (0.225 vs 0.218), fewer params (2.8 M vs 7.7 M), fewer FLOPs (12.2 vs 14.7). The MoE's parameter/compute efficiency and P2's resolution stack.

Mechanism — why it works, and why at 640 resolution

(a) Stride is the resolution knob for tiny objects. Detection quality on an object scales with its grid footprint. Halving the stride (P3→P2, 8→4) doubles the footprint, moving sub-grid targets into the learnable regime. This is why the gains land on the smallest classes and cost the largest one — a finer head trades a little coarse-scale capacity for fine-scale recall.

(b) imgsz and stride are substitutes, not independent. footprint = object_px / stride, and raising input resolution raises object_px proportionally. A 7 px object at 640 (P3 footprint ≈ 0.9) becomes 14 px at 1280 (P3 footprint ≈ 1.75) — i.e. imgsz hands the baseline a "virtual P2 head" via pixels. This is confirmed empirically: at 1280 the P2 gain collapses to ~+0.8 mAP50 (near-nil for +41% FLOPs), because the resolution already supplies the footprint; at 640 P2 clearly wins. Conclusion: the P2 head is a low-resolution optimization — evaluate and deploy at 640 (the real-time regime), where baseline@1280 "matching" is not a valid competitor (it costs ~4× FLOPs and breaks real-time).

(c) MoE and P2 are orthogonal. ES-MoE improves which features and how much compute per region; P2 improves the spatial grid those features are read out on. One raises feature quality; the other raises sampling density. They attack different terms, so they add — which is exactly what EsMoE-N-P2 shows (it beats both the MoE-only and the P2-on-dense-backbone models).

FLOPs — P2 vs scaling up to S-tier

Adding P2 keeps the model firmly sub-S-tier. Measured at 640:

Model Params GFLOPs@640 Stride-4 head?
EsMoE-N-P2 2.8 M 12.2
v0.1-N-P2 7.7 M 14.7
YOLO11-S 9.5 M 21.7
YOLO12-S 9.3 M 21.7
YOLOv10-S 8.1 M 25.1
YOLOv8-S 11.2 M 28.8
YOLO-Master-S 29.2 M 34.7
  • N→P2 costs +4.8 GFLOPs; N→S costs +24.8 GFLOPs. P2 is ~1/5 of a scale-up — and it targets the tiny-object bottleneck that scaling up does not: every S-tier detector above (including YOLO-Master-S) is still P3/P4/P5, still stride-8, still resolution-blind on sub-8px targets. They spend their extra FLOPs on channels/depth (general capacity), not sampling density.
  • EsMoE-N-P2 (12.2 GFLOPs) undercuts the leanest S-tier by ~44% and YOLO-Master-S by ~65%, while adding a capability none of them have. On the VisDrone/tiny-object frontier it dominates the S-tier on cost.
  • (Aside: YOLO-Master-S is the heaviest S here — 34.7 GFLOPs / 29 M params — echoing the paper's limited scale-up efficiency, which further favors "add P2 to N" over "go to S".)

Caveats for reproducibility

  • EsMoE-N baseline requires dense eval. The sparse-inference eval path collapses EsMoE-N validation to ~0.01 mAP (an eval-time artifact, not the trained model). The 0.350 baseline above is the --no-sparse-eval (dense) result; the sparse run is invalid for comparison.
  • Evaluate at the training imgsz. Train/test resolution mismatch drops mAP (e.g. a 1280-trained model reads 0.325 at 640 vs 0.455 at 1280); all A/Bs here are matched.
  • High-res training is unstable. At 1280 the P2 head (~4× anchors) triggers assigner OOM and an epoch-2 NaN/router collapse that the base model's stabilization crutches recover from — another reason 640 is the right operating point.
  • The S-tier comparison is a compute-frontier argument. FLOPs are measured; S-tier VisDrone mAP is not yet run (the paper's Table 1 is Nano-only), so the accuracy-vs-FLOPs Pareto isn't plotted. Training YOLO-Master-S on VisDrone @640 would close this.

Discussion

The head is currently the one place the architecture leaves tiny-object performance on the table. Given the results, a P2/stride-4 head — especially paired with ES-MoE (EsMoE-N-P2) — looks like a high-efficiency, low-FLOPs addition for edge dployments in the real-time drone/aerial detection regime, and hence a cheaper path to small-object accuracy than scaling to S. Would the maintainers be interested in the P2 variant shipped as an optional config for the small-object datasets and hence enriching the applicability of the YOLO-Master family? I can share the full configs, and the runtime-grafted EsMoE-N-P2 generator by a submitting a PR under examples/

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions