Skip to content

fix: use bin centers, not left edges, for pLDDT/PAE/PDE classificatio… - #355

Open
Pana-TsK wants to merge 1 commit into
aqlaboratory:mainfrom
Pana-TsK:fix/confidence-bin-offset
Open

fix: use bin centers, not left edges, for pLDDT/PAE/PDE classificatio…#355
Pana-TsK wants to merge 1 commit into
aqlaboratory:mainfrom
Pana-TsK:fix/confidence-bin-offset

Conversation

@Pana-TsK

@Pana-TsK Pana-TsK commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

all_atom_plddt_loss, pae_loss, and pde_loss each discretize a continuous error value into classification bins via binned_one_hot(x, v_bins), which assigns x to whichever entry of v_bins is nearest. All three built
v_bins as bin_min + arange(no_bins) * bin_size — the left edge of each bin — instead of the bin center.

get_bin_centers (core/metrics/confidence.py), which decodes predicted bin probabilities back into pLDDT/PAE/PDE scores at inference time, and all_atom_distogram_loss's target-binning both correctly use bin_min + bin_size/2 + arange(no_bins) * bin_size.

Impact

The mismatch meant these three losses were trained against a grid shifted half a bin width from the grid their own output is decoded against, on essentially every training step (confidence losses are enabled by default). This is a systematic, silent miscalibration of every reported pLDDT/PAE/PDE score — it doesn't affect predicted coordinates (distogram/diffusion/FAPE
losses are unaffected), only the confidence heads' training signal and the scores derived from them.

Changes

  • openfold3/core/loss/confidence.py: add the bin_size / 2 offset in all_atom_plddt_loss, pae_loss, and pde_loss, mirroring the pattern distogram.py already uses correctly.

Testing

Added one regression test per loss in openfold3/tests/test_confidence_loss.py that patches binned_one_hot to capture the v_bins it's actually called with and asserts it matches get_bin_centers's output for the same bin_min/bin_max/no_bins. Confirmed each new test fails against the pre-fix code and passes after. Full existing test suite for these losses (test_confidence_loss.py, test_distogram_loss.py, test_diffusion_loss.py, test_loss_weights.py) passes with no regressions. ruff format --check and ruff check clean.

…n targets

all_atom_plddt_loss, pae_loss, and pde_loss each discretize a continuous
error value into classification bins via binned_one_hot(x, v_bins), which
assigns x to whichever entry of v_bins is nearest. All three built v_bins
as bin_min + arange(no_bins) * bin_size -- the left edge of each bin --
instead of the bin center. get_bin_centers (core/metrics/confidence.py),
which decodes predicted bin probabilities back into pLDDT/PAE/PDE scores
at inference time, and all_atom_distogram_loss's target-binning both
correctly use bin_min + bin_size/2 + arange(no_bins) * bin_size.

The mismatch meant these three losses were trained against a grid shifted
half a bin width from the grid their own output is decoded against, on
essentially every training step (confidence losses are enabled by
default) -- a systematic, silent miscalibration of every reported
pLDDT/PAE/PDE score.

Fix mirrors distogram.py's existing correct pattern. Added a regression
test per loss that patches binned_one_hot to capture the v_bins it's
actually called with and asserts it matches get_bin_centers's output;
confirmed each test fails against the pre-fix code and passes after.
@jandom
jandom requested a review from gnikolenyi August 6, 2026 11:42
@jandom

jandom commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Looping in @gnikolenyi@Pana-TsK you're absolutely on a roll here, well done!

@jandom jandom added bug Something isn't working science Discussions about scientific aspects of OpenFold3 labels Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working science Discussions about scientific aspects of OpenFold3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants