Skip to content

Fix nondeterministic behavior in NMS#143

Open
Kaminyou wants to merge 1 commit into
MPI-Dortmund:mainfrom
Kaminyou:fix/nms_mask_initialization
Open

Fix nondeterministic behavior in NMS#143
Kaminyou wants to merge 1 commit into
MPI-Dortmund:mainfrom
Kaminyou:fix/nms_mask_initialization

Conversation

@Kaminyou

@Kaminyou Kaminyou commented Nov 2, 2025

Copy link
Copy Markdown

When using two or more identical reference points, the number of picked particles could vary across runs. For example:

Particles of class ref_0.mrc: 3807 (before NMS: 3833)
Particles of class ref_1.mrc: 3816 (before NMS: 3833)
Particles of class ref_2.mrc: 3816 (before NMS: 3833)
Particles of class ref_3.mrc: 3816 (before NMS: 3833)
...

This inconsistency was caused by uninitialized memory in the NMS implementation:

iou_mask = np.empty(len(boxes_data), dtype=int)  # <-- Problem
iou_mask_close = ious > nms_threshold
iou_mask[close_indicis] = iou_mask_close
iou_mask[i] = 0  # ignore current
iou_mask = iou_mask == 1
boxes_data[iou_mask, 6] = 0

np.empty() creates an uninitialized array whose contents are random values left over in memory.
If any of those uninitialized elements happen to be 1, they will be interpreted as True after
iou_mask = iou_mask == 1, causing over-suppression of unrelated boxes and thus nondeterministic results.

Reproducibility

To confirm this behavior, you can insert the following lines to inspect the uninitialized array:

iou_mask = np.empty(len(boxes_data), dtype=int)
cnt_one = (iou_mask == 1).sum()
if cnt_one >= 1:
    print("error", cnt_one)

Running this snippet often prints nonzero counts, demonstrating that np.empty may contain random 1s even before any assignment.

Fixed Implementation

iou_mask = np.zeros(len(boxes_data), dtype=bool)
iou_mask[close_indicis] = ious > nms_threshold
iou_mask[i] = False
boxes_data[iou_mask, 6] = 0

This ensures all non-neighbor elements start as False, removing random suppression and guaranteeing deterministic, consistent NMS results across runs.
The output should be always the same.

Particles of class ref_0.mrc: 3821 (before NMS: 3833)
Particles of class ref_1.mrc: 3821 (before NMS: 3833)
Particles of class ref_2.mrc: 3821 (before NMS: 3833)
Particles of class ref_3.mrc: 3821 (before NMS: 3833)
...

@GavinR1

GavinR1 commented Nov 2, 2025

Copy link
Copy Markdown
Contributor

Thanks for posting this fix, I'll try to reproduce the issue and check the fix this week and then merge it if all is working on our end too.

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.

2 participants