Skip to content

Pass rect=False on the CPU/CUDA branch of the YOLOv8 accuracy example - #22

Open
JESUSROYETH wants to merge 1 commit into
memryx:releasefrom
JESUSROYETH:radar/detect-yolov8-rect-parity
Open

Pass rect=False on the CPU/CUDA branch of the YOLOv8 accuracy example#22
JESUSROYETH wants to merge 1 commit into
memryx:releasefrom
JESUSROYETH:radar/detect-yolov8-rect-parity

Conversation

@JESUSROYETH

Copy link
Copy Markdown

In accuracy_calculation/detect_yolov8, the MXA branch runs with rect=False and the CPU/CUDA baseline runs with the default, so the two sides of the comparison do not preprocess the images in the same way.

The default is easy to miss because it is not the one in the config file. ultralytics/cfg/default.yaml says rect: False, but Model.val() overrides it with custom = {"rect": True} (ultralytics/engine/model.py:629 in the 8.3.161 pinned in the README). So the explicit rect=False on the MXA branch looks like it is only repeating the default, but it is the only branch that actually gets it.

And rect=True changes more than the padding. Batches are grouped by aspect ratio and each one gets its own shape, rounded up to a multiple of the stride with pad=0.5 (ultralytics/data/base.py). On COCO val2017 that gives 23 distinct input shapes at the default batch of 16, and the long side ends at 672 instead of 640. With rect=False every image is a fixed 640x640 letterbox, which is the only shape a DFP can take — on the yolov8m.dfp in the zip this README links, Dfp.input_shapes is [[640, 640, 1, 3]], a single entry.

What I measured

I ran this example as it is, on a real MX3 (M.2, 4 chips, memryx 2.2.5, driver 1.3.13.1) with the precompiled yolov8m.dfp and yolov8m_post.onnx from the zip, over the full COCO val2017. Then the baseline side on the same box, same ultralytics, same 5000 images, pycocotools mAP50-95:

yolov8m, COCO val2017, n=5000 mAP50-95
baseline as the script runs it (model.val(), so rect=True) 50.323
baseline with rect=False, this PR 50.217
MXA on the chip 49.910

The MXA number matches the 49.9 in the tutorial table, so the accelerator side reproduces and none of this is about the chip. On the baseline side the difference between the two rows is 0.106 points, and that is the part of the reported gap that comes from the harness and not from the MXA.

One thing I cannot resolve from outside: the 50.2 you publish sits closer to my rect=False row than to my rect=True one. The tutorial documents plain model.val() for that baseline, and that is the rect=True path. So the more likely explanation is the usual 0.1 of drift between my CPU and your GPU, and between ultralytics versions, not a different code path. Either way I am not saying the published table is wrong — the claim is only that the script as written cannot separate the two effects.

Across four stock checkpoints, isolating rect with batch 16 on both sides (ultralytics 8.4.115):

model rect=True rect=False difference
yolov8n 37.359 37.309 0.050
yolov8s 44.983 44.960 0.023
yolo11n 39.415 39.289 0.126
yolo11s 46.917 46.618 0.299

Same direction in the four .. I would not call it a trend by model size, yolov8s comes out smaller than yolov8n so it is not simply "bigger model, bigger gap". What is consistent is the sign: the branch left on the default is always the one that scores higher, so the harness makes the gap against your own accelerator bigger, not smaller.

Why the fix goes on the CPU branch and not the MXA one

A DFP is compiled for one fixed input shape, so the MXA branch cannot take 23 of them without 23 DFPs. Its rect=False is a requirement and not an oversight, and aligning the two branches the other way would break the accelerator side.

Changes

One argument on the CPU/CUDA branch, with the reason in a comment above it. The MXA branch is untouched. The BATCH_SIZE difference between the branches (8 on MXA, the default 16 on CPU) stays as it is: I measured it and it changes nothing once both sides use rect=False, since every image goes to the same 640x640 and the batch no longer decides the shape.

Validation

Controls, all on the full 5000 images: repeating a rect=True run returns the identical number to the last digit, so these differences are not run-to-run noise. rect=False at batch 1 matches rect=False at batch 16 to nine decimals, which is the batch check above. And after reinstalling ultralytics from scratch the same run reproduces bit for bit.

I also re-ran the yolov8n and yolo11s pairs on ultralytics 8.3.152 in a separate venv — not the exact 8.3.161 pinned here, but from the same 8.3 line — to check the numbers are not an artefact of the newer release I measured on. The gaps come out the same to four decimals, 0.0496 and 0.2990.

The same asymmetry is in memryx/Yolo11-MXA-Optimized, at val.py lines 23-30 against 33-36, and I am sending the same one-line change there.

It is also in the tutorial this README links to, at https://developer.memryx.com/tutorials/accuracy/yolov8_accuracy/yolov8_accuracy.html — it gives plain model.val() as the baseline command and model.val(validator=Mxa...Validator, batch=1, rect=False) for MXA, and there it is in all three tasks, detect and segment and pose, not only detect. That page is not in this repo so I cannot include it in this PR, but it needs the same one-line change on your side. Otherwise the docs keep telling people to run the comparison the way this PR is fixing.

I'm happy to adjust this if you prefer a different shape for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant