Skip to content

Fix sign toggle in removal-based interpretability metrics - #1196

Open
DarylOkeke wants to merge 2 commits into
sunlabuiuc:masterfrom
DarylOkeke:fix/interp-negative-class-sign-toggle
Open

Fix sign toggle in removal-based interpretability metrics#1196
DarylOkeke wants to merge 2 commits into
sunlabuiuc:masterfrom
DarylOkeke:fix/interp-negative-class-sign-toggle

Conversation

@DarylOkeke

@DarylOkeke DarylOkeke commented Aug 20, 2026

Copy link
Copy Markdown

RemovalBasedMetric.compute() aliased y_probs instead of copying it, so the in-place negation of NEGATIVE-class samples re-flipped the sign on every percentage in the loop — the score at 20% comes out 0.0113 with percentages=[20] but 1.0088 with [10, 20]

clone y_probs and ablated_probs before negating (the negation itself is correct, it just needed a copy), plus a test that a percentage's score doesn't depend on its position in the list. Fails at 0.997 absolute difference without the fix

only affects filters that emit SampleClass.NEGATIVE, so the default threshold_sample_filter is fine but examples/interpretability/custom_sample_filter.py isn't

note: could also hoist the negation out of the loop since it doesn't depend on the percentage, kept it to the two clones to stay small

original_class_probs aliased y_probs, which is computed once before the loop over percentages. Negating NEGATIVE-class entries in place therefore flipped the sign on every iteration instead of applying it per percentage, so a sample's score depended on where its percentage sat in the list.

Clone before negating. Same for ablated_probs, whose in-place negation also corrupted the debug output that prints it as P(class=1).

@lehendo lehendo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not approved actually. Pls look at the comments below.

@lehendo lehendo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually wait, can you make an extra change one sec.

Can you just add this to your PR:

neg_mask = evaluated_drops < 0 inside the if debug and return_per_percentage: block (~line 496) reuses the neg_mask name from line 402, which is read again on the next loop iteration (lines 457/460).

since if/for don't create new scopes, debug=True with multiple percentages would silently clobber the real mask mid-loop.

@lehendo

lehendo commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Also unsure why your PR isn't triggering the PR checks. Make sure your branch is updated and all of that.

@DarylOkeke

Copy link
Copy Markdown
Author

Actually wait, can you make an extra change one sec.

Can you just add this to your PR:

neg_mask = evaluated_drops < 0 inside the if debug and return_per_percentage: block (~line 496) reuses the neg_mask name from line 402, which is read again on the next loop iteration (lines 457/460).

since if/for don't create new scopes, debug=True with multiple percentages would silently clobber the real mask mid-loop.

Fixed.

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