{"slug": "first-internal-integration-of-the-new-api", "title": "First internal integration of the new API", "summary": "A developer merged two major pull requests into the sbi repository, introducing the first concrete builder class and integrating it into Neural Posterior Estimation (NPE) trainers. The DensityEstimatorBuilder replaces opaque factory closures with a typed, inspectable interface, and the team deferred a premature abstraction after mentor feedback. The integration includes a deprecation path for backward compatibility.", "body_md": "Hello again! The GSoC coding period is in full swing, and weeks 3 and 4 have been absolutely packed with progress.\n\nFollowing up on the foundational work from my first PR, I have just successfully merged two major PRs ([#1877](https://github.com/sbi-dev/sbi/pull/1877) and [#1882](https://github.com/sbi-dev/sbi/pull/1882)) into the gsoc-2026 branch for [sbi](https://github.com/sbi-dev). These PRs introduce the first concrete builder class and wire it directly into the core Neural Posterior Estimation (NPE) trainers.\n\nHere is a dive into what I built, the technical hurdles, and a very valuable lesson I learned about software architecture along the way.\n\n`DensityEstimatorBuilder`\n\nThe primary goal of this phase was to replace the old, opaque `posterior_nn()`\n\nand `likelihood_nn()`\n\nfactory closures with something typed, inspectable, and much more robust.\n\nTo solve this, I introduced the `DensityEstimatorBuilder`\n\n. It inherits from the base contract we established in Week 1 and serves as the unified entry point for creating neural networks in `sbi`\n\n. Using the `__post_init__`\n\nmethod in Python dataclasses, it immediately validates the model name against a `_VALID_DENSITY_MODELS`\n\nset, failing early if the user provides an unknown architecture.\n\nInitially, our plan dictated that the `build()`\n\nmethod should take a `BuildContext`\n\nobject. The idea was that this context would hold all necessary information, including pre-computed z-scoring stats, and pass it neatly down the chain.\n\nHowever, as I implemented the body of the `build()`\n\nmethod, my mentor [Jan Teusen](https://github.com/janfb) noticed that the `context`\n\nparameter wasn't actually being used. Every piece of information the builder needed could be derived directly from the raw `batch_theta`\n\nand `batch_x`\n\ntensors.\n\nWe realized that forcing the `BuildContext`\n\ninto this signature was a **premature abstraction**.\n\nInstead of holding onto a design just because it was the original plan, we decided to defer the context object entirely until the z-scoring stats are actually pre-computed in a later phase. We updated our roadmap and simplified the `build`\n\nsignature.\n\n``` python\ndef build(self, batch_theta: Tensor, batch_x: Tensor):\n    pass\n```\n\nIt was a great decision to defer the `context`\n\nimplementation to work on the breadth first and then move towards depth.\n\nWith the builder merged, the next step was integration. I updated `PosteriorEstimatorTrainer`\n\n, `NPE_B`\n\n, `NPE_C`\n\n, and `MNPE`\n\nto accept the new `DensityEstimatorBuilder`\n\ninstead of relying solely on strings or callables.\n\nTo maintain backward compatibility while moving the API forward, a graceful deprecation path was implemented. If a user passes a string (e.g., `\"maf\"`\n\n), the code still works perfectly, but it now emits a `FutureWarning`\n\n.\n\n```\nif density_estimator is None:\n    self._build_neural_net = self._wrap_builder(DensityEstimatorBuilder(model=\"maf\"))\nelif isinstance(density_estimator, str):\n    warnings.warn(\n        \"Passing a string for `density_estimator` is deprecated. \"\n        \"Use DensityEstimatorBuilder(model=...) instead.\",\n        FutureWarning,\n        stacklevel=3,\n    )\n    self._build_neural_net = posterior_nn(model=density_estimator)\nelif isinstance(density_estimator, _EstimatorBuilderBase):\n    self._build_neural_net = self._wrap_builder(density_estimator)\nelse:\n    self._build_neural_net = density_estimator\n```\n\nThe code review for [PR #1882](https://github.com/sbi-dev/sbi/pull/1882) was intense but incredibly rewarding. My mentor provided feedback on how to write tests that are not just concise, but strong and explicit in their intent.\n\nFor example, I originally wrote a test that checked if passing a callable avoided triggering the deprecation warning. But I wasn't actually asserting that no warning was thrown, I was just running the code and assuming silence meant success.\n\nMy mentor showed me how to use `warnings.catch_warnings()`\n\nwith a strict filter to instantly fail the test if a `FutureWarning`\n\nleaked through:\n\n``` python\nimport warnings\n\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"error\", FutureWarning)\n    inference = NPE_C(prior, density_estimator=builder, show_progress_bars=False)\n```\n\nWe also did a deep dive into correct type hinting and managing default arguments. I initially left `density_estimator=\"maf\"`\n\nas the default argument in the `NPE_C`\n\ninitialization. My mentor pointed out that this would cause the deprecation warning to fire every single time a user initialized the class without arguments! The fix was to change the type hint default to `None`\n\nand handle the `\"maf\"`\n\nfallback inside the logic block.\n\nWeeks 3 and 4 were a massive leap forward for the API refactor. We now have a working, integrated builder that correctly handles all continuous density estimators.\n\nNext up, I will be tackling the remaining likelihood and classifier builders. Thanks for following along on this journey, and see you in the next update!", "url": "https://wpnews.pro/news/first-internal-integration-of-the-new-api", "canonical_source": "https://dev.to/satwiksps/first-internal-integration-of-the-new-api-25ii", "published_at": "2026-06-29 17:47:42+00:00", "updated_at": "2026-06-29 18:19:06.868767+00:00", "lang": "en", "topics": ["machine-learning", "developer-tools"], "entities": ["sbi", "Jan Teusen", "DensityEstimatorBuilder", "Neural Posterior Estimation", "NPE_B", "NPE_C", "MNPE", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/first-internal-integration-of-the-new-api", "markdown": "https://wpnews.pro/news/first-internal-integration-of-the-new-api.md", "text": "https://wpnews.pro/news/first-internal-integration-of-the-new-api.txt", "jsonld": "https://wpnews.pro/news/first-internal-integration-of-the-new-api.jsonld"}}