Skip to content

Fix mislabeled multiclass metrics in image learner report - #176

Merged
paulocilasjr merged 3 commits into
mainfrom
fix/multiclass-accuracy-metric-labels
Jul 21, 2026
Merged

Fix mislabeled multiclass metrics in image learner report#176
paulocilasjr merged 3 commits into
mainfrom
fix/multiclass-accuracy-metric-labels

Conversation

@paulocilasjr

Copy link
Copy Markdown
Contributor

Fix mislabeled multiclass metrics in the Image Learner report

Problem

For multiclass models, the report's "Accuracy" and "Micro F1-score" disagreed (e.g. 0.8044 vs 0.8947 on HAM10000), which is impossible for single-label multiclass classification, where micro-F1 ≡ accuracy.

An audit traced this to Ludwig 0.10.1, whose stats the tool relabels verbatim:

  • accuracy is not accuracy. Ludwig's CategoryAccuracy subclasses torchmetrics MulticlassAccuracy without an average argument, inheriting the default average="macro". The reported value is therefore macro-averaged per-class recall (balanced accuracy). Confirmed empirically: "Accuracy" always equals the "Macro Recall" row to 4 decimals.
  • accuracy_micro is the true sample-level accuracy (average="micro"), identical to micro precision/recall/F1 and token_accuracy.
  • avg_precision_weighted / avg_recall_weighted are miscomputed upstream. Ludwig's ConfusionMatrix.stats() (ludwig/utils/eval_utils.py) passes average="micro" for both, so these rows silently duplicated the micro values instead of being support-weighted.
  • Multiclass roc_auc (MulticlassAUROC) is macro-averaged but was labeled plain "ROC-AUC".

Changes

  • constants.py: add MULTICLASS_METRIC_DISPLAY_NAME_OVERRIDES — for category outputs, accuracy → "Balanced Accuracy (Macro Recall)", accuracy_micro → "Accuracy", roc_auc → "Macro ROC-AUC".
  • html_structure.py: format_metric_display_name() accepts output_type and applies the overrides only for multiclass; threaded through all three summary tables. Help modal updated (Balanced Accuracy entry added, obsolete Token Accuracy entry removed).
  • utils.py: for multiclass test stats, exclude avg_precision_weighted and avg_recall_weighted (wrong values, per the Ludwig bug above) and token_accuracy (exact duplicate of accuracy); exclusions now also apply to the flattened overall_stats.

No metric values are recomputed — only labels and row selection change. Binary and regression reports are untouched.

Ludwig 0.10.1's category 'accuracy' inherits torchmetrics MulticlassAccuracy's
default average='macro', so it is macro-averaged per-class recall (balanced
accuracy), not sample-level accuracy; 'accuracy_micro' is the true accuracy.
Relabel both for multiclass reports (binary labels unchanged), label multiclass
roc_auc as Macro ROC-AUC, and drop from the test summary:
- avg_precision_weighted / avg_recall_weighted: computed with average='micro'
  upstream (Ludwig eval_utils.py bug), silently duplicating micro values
- token_accuracy: exact duplicate of accuracy_micro

Also update the metrics help modal accordingly.
"""
if metric_key == "hits_at_k":
return f"Hits@{int(top_k)}"
if output_type == "category" and metric_key in MULTICLASS_METRIC_DISPLAY_NAME_OVERRIDES:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This new category-aware branch is bypassed by the experiment configuration table: format_config_table_html() still calls format_metric_display_name() for validation_metric without passing its already-available output_type (around lines 190–192). As a result, a multiclass run configured with Ludwig’s raw accuracy metric still reports Validation Metric: Accuracy, while the performance tables correctly call the same metric Balanced Accuracy (Macro Recall). I confirmed the mismatch directly on this PR head. Please pass output_type at that call site and add a multiclass configuration-table regression test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Fixed it.

format_config_table_html() already received output_type but did not forward it
to format_metric_display_name(), so a multiclass run validated on Ludwig's raw
'accuracy' reported 'Validation Metric: Accuracy' while the performance tables
called the same metric 'Balanced Accuracy (Macro Recall)'.

Pass output_type at that call site and add a multiclass configuration-table
regression test covering the override, agreement with the performance-table
label, accuracy_micro, binary/unset output types, and top_k resolution.
build_train_validation_plots() hardcoded 'Accuracy across epochs' and
'ROC-AUC across epochs', so multiclass reports charted Ludwig's macro-averaged
accuracy and ROC-AUC under labels that contradicted the performance tables
directly above them.

Pass output_type from ludwig_backend and reuse the shared multiclass overrides
for the curve titles, the y-axis labels and the overfitting-gap plot. Also plot
accuracy_micro, which was collected in training statistics but never charted, so
the true sample-level accuracy curve is now shown alongside balanced accuracy.
Binary and regression titles are unchanged. Adds regression tests for both the
category and binary/unset cases.
@paulocilasjr

Copy link
Copy Markdown
Contributor Author

Also fixed: learning-curve plots hardcoded "Accuracy"/"ROC-AUC" titles, so multiclass reports charted macro values under labels that contradicted the tables above them. build_train_validation_plots() now takes output_type and reuses the same overrides. Additionally plots accuracy_micro, which was collected but never charted.

@paulocilasjr
paulocilasjr merged commit 0d68599 into main Jul 21, 2026
11 checks passed
@paulocilasjr
paulocilasjr deleted the fix/multiclass-accuracy-metric-labels branch July 21, 2026 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants