Skip to content

Fix division by zero in math operations - #253

Open
Ayushhgit wants to merge 1 commit into
mllam:mainfrom
Ayushhgit:fix-math-div-zero
Open

Fix division by zero in math operations#253
Ayushhgit wants to merge 1 commit into
mllam:mainfrom
Ayushhgit:fix-math-div-zero

Conversation

@Ayushhgit

@Ayushhgit Ayushhgit commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Describe your changes

Summary of the changes:

  • Added a 1e-6 epsilon to the output of torch.nn.functional.softplus in [base_graph_model.py].
  • Added a 1e-8 epsilon to the self.feature_weights inverse square root calculation inside ARModel.__init__.

Motivation and context:
These changes resolve two separate division-by-zero crashes:

  1. When computing the pred_std using softplus, inputs $\le -80$ in float32 will evaluate exactly to 0.0. This zero denominator causes cascading NaN outputs instantly destroying training across metrics like wmse or wmae.
  2. When users specify a manual feature weight of 0.0 for specific state variables they want the model to ignore, creating per_var_std triggers a scalar division by zero, crashing model initialization. The epsilons bring numerical stability against these mathematical singularities.

Dependencies:
None

Issue Link

N/A

Type of change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📖 Documentation (Addition or improvements to documentation)

Checklist before requesting a review

  • My branch is up-to-date with the target branch - if not update your fork with the changes from the target branch (use pull with --rebase option if possible).
  • I have performed a self-review of my code
  • For any new/modified functions/classes I have added docstrings that clearly describe its purpose, expected inputs and returned values
  • I have placed in-line comments to clarify the intent of any hard-to-understand passages of my code
  • I have updated the README to cover introduced code changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have given the PR a name that clearly describes the change, written in imperative form (context).
  • I have requested a reviewer and an assignee (assignee is responsible for merging). This applies only if you have write access to the repo, otherwise feel free to tag a maintainer to add a reviewer and assignee.

Checklist for reviewers

Each PR comes with its own improvements and flaws. The reviewer should check the following:

  • the code is readable
  • the code is well tested
  • the code is documented (including return types and parameters)
  • the code is easy to maintain

Author checklist after completed review

  • I have added a line to the CHANGELOG describing this change, in a section
    reflecting type of change (add section where missing):
    • added: when you have added new functionality
    • changed: when default behaviour of the code has been changed
    • fixes: when your contribution fixes a bug
    • maintenance: when your contribution is relates to repo maintenance, e.g. CI/CD or documentation

Checklist for assignee

  • PR is up to date with the base branch
  • the tests pass
  • (if the PR is not just maintenance/bugfix) the PR is assigned to the next milestone. If it is not, propose it for a future milestone.
  • author has added an entry to the changelog (and designated the change as added, changed, fixed or maintenance)
  • Once the PR is ready to be merged, squash commits and merge the PR.

@joeloskarsson joeloskarsson 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.

Thanks, these are good changes to make the code more robust. Would it be possible to also add some test that checks that we don't run into numerical issues with the chosen constants?

Comment thread neural_lam/models/ar_model.py Outdated
@Ayushhgit

Copy link
Copy Markdown
Contributor Author

@joeloskarsson Thanks for the feedback! I've just pushed a commit with the updates:

Warning: Added a UserWarning in ar_model.py that alerts the user and lists the indices if any variables receive a feature weight of exactly 0.0 (excluding them from the loss). Tests: Added

test_numerical_stability.py with 5 pure tensor unit tests. These verify that the softplus epsilon (1e-6) and the feature weight epsilon (1e-8) successfully prevent exact zeros and subnormals, keeping downstream loss metrics (wmse, wmae, per_var_std) perfectly finite even with worst-case or zero-weight inputs. Let me know if you need anything else!

@sadamov sadamov added the bug Something isn't working label Mar 1, 2026
@sadamov

sadamov commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

please link this issue in your PR description: #526

Re-applies @Ayushhgit's PR mllam#253 onto current main, scoped down to the
clear-cut feature-weights fix and rebased onto the post-mllam#208 layout:

- The original PR also added `+ 1e-6` to `softplus(pred_std_raw)` to
  guard against float32 underflow at very negative `pred_std_raw`.
  That overlapped with mllam#523's `* self.diff_std` scaling on the same
  line and is largely redundant once pred_std starts on the empirical
  scale, so dropped here to avoid coupling the two PRs.

- Target file `models/ar_model.py` is gone since mllam#208; fix is applied
  at `models/module.py:120` next to the existing `per_var_std`
  registration.

- Use `torch.finfo(torch.float32).eps` instead of a hard-coded `1e-8`
  for the sqrt epsilon, matching the eps choice used a few lines below
  for `state_std` / `forcing_std`.

- Slimmed tests/test_numerical_stability.py to the 3 feature-weights
  assertions (finite output, eps does not perturb non-zero weights,
  warning fires with the zero index). Dropped the softplus / wmae /
  wmse integration tests since the softplus piece is no longer in
  scope.

Refs mllam#526.

Co-Authored-By: Ayush <Ayushhgit@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sadamov
sadamov force-pushed the fix-math-div-zero branch from c80a1b7 to ae8550d Compare June 6, 2026 18:33

@sadamov sadamov 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.

Thanks @Ayushhgit, rebased onto current main and scoped down. Two changes:

  1. Dropped the softplus(pred_std_raw) + 1e-6 piece - that line overlaps with #523's * self.diff_std scaling, and once pred_std starts on the empirical scale via #523 the underflow concern is largely moot. Better to land the two ideas separately so they don't fight.
  2. Switched to torch.finfo(torch.float32).eps for the sqrt eps (matches the existing state_std / forcing_std epsilon choice a few lines below).

tests requested by @joeloskarsson have been added before. please review

Refs #526. Merging after CI is green.

@sadamov sadamov self-assigned this Jun 6, 2026
@sadamov
sadamov self-requested a review June 6, 2026 18:44
@joeloskarsson

Copy link
Copy Markdown
Collaborator

Thanks for adding the tests, but I am a bit confused here since they don't call any of the actual code. E.g. mirroring the per_var_std calculations separately in the test file seems very bad to maintain. Testing the numerical aspect is good, but we should do it running through the actual code used when training models. If this code is not structured such that it can be tested (requiring a mirroring function), then we should restructure it so that is possible.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants