dataset_nuscenes: give each sample a COCO image id that survives a new process - #7
Open
egeboy35 wants to merge 1 commit into
Open
dataset_nuscenes: give each sample a COCO image id that survives a new process#7egeboy35 wants to merge 1 commit into
egeboy35 wants to merge 1 commit into
Conversation
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
egeboy35
force-pushed
the
fix/nuscenes-image-id-is-reproducible
branch
2 times, most recently
from
September 1, 2026 12:28
0cd452c to
3ee963f
Compare
…w process
dataset_nuscenes.py:433 builds every target's COCO image id as
'image_id': torch.tensor([hash(sample_token) % 1000000]),
and cocoevaluator.py keys both halves of the evaluation on it: the ground
truth at convert_to_coco_api line 300, the predictions at `res[image_id] =
out` on line 370.
`hash()` on a str is salted per interpreter (PEP 456). One token, six fresh
interpreters:
PYTHONHASHSEED=0 -> 489194
PYTHONHASHSEED=1 -> 812316
PYTHONHASHSEED=2 -> 270356
PYTHONHASHSEED=random -> 473704
PYTHONHASHSEED=random -> 887793
PYTHONHASHSEED=random -> 561686
Six ids for one sample. So a prediction file written in one run cannot be
scored against ground truth rebuilt in another, and the two processes of a
distributed run disagree about which image is which. That is the part of this
that does not get smaller with a bigger machine or a smaller dataset.
The 1e6 range is the second, milder half. Over the 34,149 keyframes of
v1.0-trainval, a 1e6 range loses about 555 ids to collisions -- "about",
because the exact count depends on the salt: two runs here gave 564 and 594.
The instability shows up even in the measurement of the collision rate.
I would rather give the honest size of that half than the dramatic one. Run
through this repository's own convert_to_coco_api and CocoEvaluator, a
detector whose predictions ARE the ground truth scores
one id per sample (control) mAP 1.0000
ids drawn from 1e6, 4,000 samples mAP 0.9901 (0.99% low)
every id shared by two samples mAP 0.5050 (49.5% low)
The last row is not the real rate -- it is an exaggeration that isolates the
mechanism, since `res[image_id] = out` keeps only the last of a colliding pair
while the ground truth keeps both. At realistic rates the collision costs about
a point; the reproducibility is the reason to change the line.
`stable_image_id` takes 13 hex digits of sha256: identical in every process,
and 52 bits keeps every id an exact JavaScript integer for COCO JSON consumers
while putting collisions out of reach -- 0 over 1,000,000 tokens, measured.
Considered and rejected: crc32 (stable, but starts colliding above ~100k), and
passing the sample index (unique by construction, but it changes get_target's
signature and makes the id depend on --max-samples rather than on the sample).
Adds detection/test_nuscenes_image_id.py -- 12 tests, no download, no GPU:
12 passed.
One thing this suite cannot do, and I would rather say so than imply
otherwise: it does not run red against main. `stable_image_id` is new, so
against the current file the suite fails to import and pytest reports a
collection error rather than a set of behavioural failures. What stands in for
that is test_the_builtin_hash_really_is_unstable_here, which measures `hash()`
across seeds directly and would fail if the premise of this change were wrong,
and the mAP figures above, which come from the repository's own evaluator.
`cv2` is stubbed in the test only when genuinely absent -- dataset_nuscenes
imports it at module scope and no code under test touches it. A test reports
whether the stub was used, so a stubbed run cannot be mistaken for a clean one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
egeboy35
force-pushed
the
fix/nuscenes-image-id-is-reproducible
branch
from
September 1, 2026 12:43
3ee963f to
702af04
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
dataset_nuscenes.py:433builds every target's COCO image id asand
cocoevaluator.pykeys both halves of the evaluation on it: the ground truth atconvert_to_coco_apiline 300, the predictions atres[image_id] = outon line 370.The id is not the same twice
hash()on astris salted per interpreter (PEP 456). One token, six fresh interpreters:Six ids for one sample. A prediction file written in one run cannot be scored against ground truth rebuilt in another, and the two processes of a distributed run disagree about which image is which. This is the half that does not shrink with a bigger machine or a smaller dataset.
The 1e6 range is the milder half, and I would rather give its honest size
Over the 34,149 keyframes of v1.0-trainval a 1e6 range loses about 555 ids to collisions — "about", because the exact count depends on the salt: two runs here gave 564 and 594. The instability shows up even in the measurement of the collision rate.
Run through this repository's own
convert_to_coco_apiandCocoEvaluator, a detector whose predictions are the ground truth scores:The last row is not the real rate — it is an exaggeration that isolates the mechanism, since
res[image_id] = outkeeps only the last of a colliding pair while the ground truth keeps both. At realistic rates the collision costs about a point. The reproducibility is the reason to change the line.The change
stable_image_idtakes 13 hex digits of sha256: identical in every process, and 52 bits keeps every id an exact JavaScript integer for COCO JSON consumers while putting collisions out of reach — 0 over 1,000,000 tokens, measured.Considered and rejected:
crc32(stable, but starts colliding above ~100k), and passing the sample index (unique by construction, but it changesget_target's signature and makes the id depend on--max-samplesrather than on the sample).Tests
Adds
detection/test_nuscenes_image_id.py— 12 tests, no download, no GPU: 12 passed.One thing this suite cannot do, and I would rather say so than imply otherwise: it does not run red against
main.stable_image_idis new, so against the current file the suite fails to import and pytest reports a collection error rather than behavioural failures. What stands in for that istest_the_builtin_hash_really_is_unstable_here, which measureshash()across seeds directly and would fail if the premise of this change were wrong — plus the mAP figures above, which come from your own evaluator.cv2is stubbed in the test only when genuinely absent:dataset_nuscenesimports it at module scope and no code under test touches it. A test reports whether the stub was used, so a stubbed run cannot be mistaken for a clean one.