Skip to content

Add RatioEstimatorBuilder for NRE trainers and base class improvements#1920

Merged
janfb merged 19 commits into
sbi-dev:gsoc-2026from
satwiksps:nn-builder-refactor-pr-five
Jul 22, 2026
Merged

Add RatioEstimatorBuilder for NRE trainers and base class improvements#1920
janfb merged 19 commits into
sbi-dev:gsoc-2026from
satwiksps:nn-builder-refactor-pr-five

Conversation

@satwiksps

@satwiksps satwiksps commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

This PR continues the GSoC 2026 Neural Network Builder API refactor by introducing the RatioEstimatorBuilder for all four NRE trainers (NRE_A, NRE_B, NRE_C, BNRE).

Instead of passing a string like classifier="resnet" and hiding settings in kwargs, we can now pass a fully typed and clear configuration like RatioEstimatorBuilder(model="resnet", hidden_features=64) to use linear, MLP, or ResNet models. Passing None will silently default to a ResNet builder to keep the old behavior, while using the old string arguments is now deprecated.

Files Changed

estimator_configs.py

  • New RatioEstimatorBuilder dataclass configures and validates linear/MLP/ResNet classifiers, with build() routing to the right function.
  • Builders are now frozen/immutable (use dataclasses.replace() to tweak), with safer extra_kwargs handling and a cleaner __repr__ that only shows what's actually set.
  • Renamed z_score_x/y to z_score_input/condition for clarity, with aliasing so it still maps correctly downstream.
  • Validates at construction time, catches bad Literal values and flags hyperparameters that don't apply to the chosen model.

nre_base.py

  • classifier now takes a RatioEstimatorBuilder (defaults to None -> ResNet); old string configs still work but warn, wrong types fail fast.
  • Added _wrap_builder to bridge the new builder API to the legacy (batch_theta, batch_x) format.

nre_a.py, nre_b.py, nre_c.py, bnre.py

  • Same classifier type hint/default update, docstrings refreshed to match.

npe_base.py, nle_base.py, mnle.py, mnpe.py

  • Deprecation warnings now point to the exact import path for the new builder, plus a small isinstance-check cleanup in mnle.py/mnpe.py.

sbi/neural_nets/__init__.py

  • Exports DensityEstimatorBuilder and MixedDensityEstimatorBuilder so those import paths actually resolve.

density_estimator_builder_test.py

  • Updated for the z_score_input/z_score_condition rename.

nre_builder_integration_test.py (new)

  • Integration tests across all NRE trainers: defaults, legacy warnings, validation, immutability, repr, z-score aliasing.

npe_nle_builder_integration_test.py

  • Keeps builder fields in sync with build-function signatures, plus z-score alias tests.

AI Usage

  • Used Grammarly for PR description refinement, VS Code Copilot for code suggestions, and GPT OSS via Antigravity for docstrings and cosmetic updates.

Does this close any issues?

N/A

Any relevant code examples, logs, or error messages?

N/A

@satwiksps
satwiksps force-pushed the nn-builder-refactor-pr-five branch from d442dce to 8d5def0 Compare July 4, 2026 10:43
@satwiksps
satwiksps marked this pull request as ready for review July 6, 2026 14:08
@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.23664% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 87.98%. Comparing base (587f922) to head (2896bdc).
⚠️ Report is 38 commits behind head on gsoc-2026.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
sbi/neural_nets/net_builders/estimator_configs.py 99.04% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           gsoc-2026    #1920      +/-   ##
=============================================
- Coverage      87.99%   87.98%   -0.02%     
=============================================
  Files            144      144              
  Lines          13499    13717     +218     
=============================================
+ Hits           11879    12069     +190     
- Misses          1620     1648      +28     
Flag Coverage Δ
fast 81.69% <99.23%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
sbi/inference/trainers/nle/mnle.py 97.05% <ø> (+4.46%) ⬆️
sbi/inference/trainers/nle/nle_base.py 97.36% <ø> (ø)
sbi/inference/trainers/npe/mnpe.py 97.05% <ø> (+7.05%) ⬆️
sbi/inference/trainers/npe/npe_base.py 93.38% <ø> (ø)
sbi/inference/trainers/nre/bnre.py 97.29% <100.00%> (+0.07%) ⬆️
sbi/inference/trainers/nre/nre_a.py 100.00% <100.00%> (ø)
sbi/inference/trainers/nre/nre_b.py 100.00% <100.00%> (ø)
sbi/inference/trainers/nre/nre_base.py 92.47% <100.00%> (+1.33%) ⬆️
sbi/inference/trainers/nre/nre_c.py 98.00% <100.00%> (+0.04%) ⬆️
sbi/neural_nets/__init__.py 61.90% <100.00%> (+1.90%) ⬆️
... and 3 more

... and 2 files with indirect coverage changes

@janfb janfb left a comment

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.

Thanks @satwiksps, overall very clean extension of the builder pattern to all four NRE trainers. great that you added the role-shape regression test (test_builder_role_shapes).

As discussed in our meeting I made several longer comments that go beyond the NRE code, mostly improvements that belong in the base class, and although this is a bit of scope creep I think this PR is the right place. It will make the the upcoming VF builder and other refactorings much easier.

Let me know if anything is unclear!

Comment thread sbi/inference/trainers/nre/nre_base.py Outdated
Comment thread sbi/neural_nets/net_builders/estimator_configs.py Outdated
Comment thread sbi/neural_nets/net_builders/estimator_configs.py Outdated
Comment thread sbi/neural_nets/net_builders/estimator_configs.py Outdated
Comment thread sbi/neural_nets/net_builders/estimator_configs.py
Comment on lines +475 to +476
embedding_net_x: Optional[Any] = None
embedding_net_y: Optional[Any] = None

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.

the type here could be narrower, e.g., nn.Module as this should always be a NN. At some point we considered allowing Callables that return a nn.Module, but that path is actually not implemented, so no need to type-support it for now. better be more narrow.

this also applies to the other *Builder subclasses.

I also checked those classes for possibly more narrower types and there are a couple of candidates (please check as well), e.g.,:

  • MixedDensityEstimatorBuilder.num_categories_per_variable (:386): downstream is Optional[Tensor] → narrow from Any to Optional[Tensor].
  • RatioEstimatorBuilder.norm_layer (:484, already Optional[Callable]): downstream is Callable[[int], nn.Module] (default nn.LayerNorm) → tighten to
    Optional[Callable[[int], nn.Module]].

_VALID_CLASSIFIER_MODELS = frozenset(get_args(CLASSIFIER_MODELS))


@dataclass

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.

When this gets changed to repr=False from the comment above, you would need to add one custom __repr__ on the base so configs read the way users wrote them. At the moment, repr(RatioEstimatorBuilder(model="resnet", hidden_features=64)) prints all 11 fields starting with the internal extra_kwargs={} and nine Nones, potentially hiding the two the user set. A base __repr__ that leads with model and omits unset/default fields yields RatioEstimatorBuilder(model='resnet', hidden_features=64). (Lives in the base, so all builders benefit.)

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.

When building the repr note that it's important to

  • Always show the discriminator (model / continuous_model), even when it equals its default, otherwise DensityEstimatorBuilder(model="maf") (maf is the default) reprs as DensityEstimatorBuilder(), hiding the one field that matters.
  • Skip empty extra_kwargs. It uses default_factory, so field.default is MISSING, not {}; a naive value == field.default check won't drop it and you get a stray extra_kwargs={}.

Comment thread sbi/neural_nets/net_builders/estimator_configs.py Outdated
Comment thread sbi/inference/trainers/nre/nre_base.py Outdated
@satwiksps satwiksps changed the title Add RatioEstimatorBuilder for NRE trainers Add RatioEstimatorBuilder for NRE trainers and base class improvements Jul 20, 2026
@satwiksps
satwiksps force-pushed the nn-builder-refactor-pr-five branch from 75f7a74 to a7c12dd Compare July 20, 2026 06:56
satwiksps added 13 commits July 20, 2026 20:07
…idation

* Converted all builder classes to use @DataClass(frozen=True, eq=False, repr=False) to ensure immutability.
* Added _reject_inapplicable_fields() to fail-fast and throw an error if a user passes hyperparameters that the chosen model's build function would silently ignore.
* Implemented a custom __repr__ that hides empty or default fields but always displays the discriminator field (like model or continuous_model).
* Replaced the None default for extra_kwargs with ield(default_factory=dict) to handle arbitrary kwargs safely.
* Renamed the z-score fields to z_score_input and z_score_condition, while using a _BUILD_KWARG_ALIASES map to maintain compatibility with downstream build functions.
* Added _literal_values() to catch typos in Literal fields immediately when the class is constructed.
* Tightened the type annotations for fields like embedding_net,
um_categories_per_variable, and
orm_layer.
* Moved the dispatch dictionaries out to module-level _density_build_fns() and _classifier_build_fns() helpers to keep the code clean and prevent circular imports.
@satwiksps
satwiksps force-pushed the nn-builder-refactor-pr-five branch from a7c12dd to 8122159 Compare July 20, 2026 14:37
@satwiksps
satwiksps requested a review from janfb July 20, 2026 17:23

@janfb janfb left a comment

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.

Looking mostly done, great! 👏

Just one missed argument and a couple of smaller improvement comments.

Comment thread sbi/inference/trainers/nre/nre_base.py Outdated
Comment thread sbi/neural_nets/net_builders/estimator_configs.py
Comment thread sbi/neural_nets/net_builders/estimator_configs.py Outdated
Comment thread sbi/neural_nets/net_builders/estimator_configs.py Outdated
Comment thread sbi/inference/trainers/npe/mnpe.py Outdated
@satwiksps
satwiksps requested a review from janfb July 22, 2026 05:57

@janfb janfb left a comment

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.

Looks good! 👏

@janfb
janfb merged commit 37d0327 into sbi-dev:gsoc-2026 Jul 22, 2026
21 checks passed
@janfb janfb mentioned this pull request Jul 22, 2026
7 tasks
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