Skip to content

feat: Add average parameter to Accuracy for per-label multilabel output - #3810

Open
zongyang078 wants to merge 3 commits into
pytorch:masterfrom
zongyang078:feat/accuracy-average-param
Open

feat: Add average parameter to Accuracy for per-label multilabel output#3810
zongyang078 wants to merge 3 commits into
pytorch:masterfrom
zongyang078:feat/accuracy-average-param

Conversation

@zongyang078

Copy link
Copy Markdown

Fixes #513

Description:
Add average parameter to Accuracy for multilabel classification, aligning its API with Precision/Recall which already support per-label output via _BasePrecisionRecall.

When average=False and is_multilabel=True, compute() returns a per-label accuracy tensor of shape (num_labels,) using elementwise comparison, rather than the default subset accuracy scalar. Default behavior (average=None) is unchanged.

Prior attempts (PR #516, PR #542) stalled in 2019 over API design — both proposed a labelwise=True boolean flag, which was rejected. This PR uses the average parameter convention already established by Precision/Recall.

Scoped to not touch Accuracy's internal structure (no _prepare_output), staying orthogonal to #3568 / #3610.

Also updates two pre-existing tests (test_accuracy.py::test_accumulator_device, test_running_average.py::test_integration_batchwise) that assumed _num_correct is always a tensor right after reset() — it's now a plain int until the first update(), matching the int | torch.Tensor pattern Precision/Recall already use for _numerator/_denominator.

Check list:

  • [ x ] New tests are added (if a new feature is added)
  • [ x ] New doc strings: description and/or example code are in RST format
  • [ x ] Documentation is updated (if required)

Add average parameter to Accuracy, aligning its API with Precision/Recall
for multilabel classification. When average=False and is_multilabel=True,
compute() returns a per-label accuracy tensor instead of a scalar.

Fixes pytorch#513
…ment

- cast() the num_correct accumulator before .item() in compute(), matching
  the pattern Precision already uses for the same int|Tensor duality
- drop a comment that just restated the line below it
- test_running_average.py: compare _num_correct in a type-agnostic way,
  since it may now be a plain int (right after reset(), before update())
  instead of always a tensor

Fixes pytorch#513
@github-actions github-actions Bot added the module: metrics Metrics module label Jul 16, 2026
def __init__(
self,
output_transform: Callable = lambda x: x,
average: bool | None = None,

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.

we can have it true by default instead of the None

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Makes sense. Switching to average: bool = True with True as the default keeps it simple. But I want to flag a naming conflict before changing the default. In Precision/Recall, average=True means "macro average," not "current default behavior." Using True to mean "subset accuracy" here would be semantically different from the sibling classes. Happy to go either way — do you think the simplicity of a plain bool outweighs the consistency concern, or should we keep None to leave room for future 'micro'/'macro' modes?

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.

Making it None doesn't make is consistent either if consistency is the problem rename it possibly

Comment on lines +320 to +321
if average is not None and average is not False:
raise ValueError("Argument average should be None or False.")

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.

Suggested change
if average is not None and average is not False:
raise ValueError("Argument average should be None or False.")
if type(average) is not bool:
raise ValueError("Argument average should be boolean")

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Will update if we go with the bool-only approach from the comment above.

Comment thread ignite/metrics/accuracy.py
y = torch.transpose(y, 1, last_dim - 1).reshape(-1, num_classes)
if self._average is False:
correct = (y == y_pred.type_as(y)).float()
self._num_correct += correct.sum(dim=0).to(self._device)

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.

I dont think we need to move it into a new device

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I kept it for consistency with the existing default path a few lines below (self._num_correct += torch.sum(correct).to(self._device)), which does the same thing. Happy to remove both if you'd prefer, or keep both — just want them consistent.

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.

Its redundant in my opinion

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

Labels

module: metrics Metrics module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Label-wise metrics (Accuracy etc.) for multi-label problems

2 participants