Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
142ff2f
[no ci] Add advice regarding moving from v1 to v2 to README.
vpratz Apr 22, 2025
9a2f338
[no ci] Add link to migration advice to docs, add info about v1
vpratz Apr 22, 2025
688f22c
[no ci] notebook tests: increase timeout, fix platform/backend depend…
vpratz Apr 23, 2025
de30009
Enable use of summary networks with functional API again (#434)
vpratz Apr 23, 2025
0eefa69
[no ci] docs: add GitHub and Discourse links, reorder navbar
vpratz Apr 25, 2025
a97b5a2
[no ci] docs: acknowledge scikit-learn website
vpratz Apr 25, 2025
8ac8aa3
[no ci] docs: capitalize navigation headings
vpratz Apr 25, 2025
8895928
[no ci] Merge remote-tracking branch 'upstream/main' into docs-migrat…
vpratz Apr 25, 2025
e590a43
[no ci] README: move details on migration to FAQ
vpratz Apr 25, 2025
076ceaf
[no ci] Change heading on migration section
vpratz Apr 25, 2025
53dda82
[no ci] docs: remove $ prefix from v1 install command
vpratz Apr 25, 2025
7ea287f
More tests (#437)
LarsKue Apr 25, 2025
42fa035
Automatically run slow tests when main is involved. (#438)
vpratz Apr 25, 2025
4cc500e
Merge branch 'dev' into fork/vpratz/docs-migration-advice
LarsKue Apr 25, 2025
86f2f5b
reintroduce symbolic tensor check in log_sinkhorn
LarsKue Apr 25, 2025
206d706
Update dispatch
stefanradev93 Apr 25, 2025
25f5c64
Update dispatching distributions
stefanradev93 Apr 25, 2025
f6a70b5
Improve workflow tests with multiple summary nets / approximators
stefanradev93 Apr 25, 2025
28652ac
Merge branch 'dev' of https://github.com/stefanradev93/BayesFlow into…
stefanradev93 Apr 25, 2025
7ce37cf
Fix zombie find_distribution import
stefanradev93 Apr 25, 2025
ea5a78d
Add readme entry [no ci]
stefanradev93 Apr 25, 2025
dc3cf81
Update README: NumFOCUS affiliation, awesome-abi list (#445)
marvinschmitt Apr 25, 2025
af38458
Merge branch 'dev' of https://github.com/stefanradev93/BayesFlow into…
stefanradev93 Apr 25, 2025
3b1c053
fix is_symbolic_tensor
LarsKue Apr 25, 2025
c638124
remove multiple batch sizes, remove multiple python version tests, re…
LarsKue Apr 25, 2025
de8e1cb
implement compile_from_config and get_compile_config (#442)
LarsKue Apr 25, 2025
16491be
Fix Optimal Transport for Compiled Contexts (#446)
LarsKue Apr 25, 2025
ec0ee2f
update dispatch tests for more coverage
LarsKue Apr 25, 2025
acf1c72
Update issue templates (#448)
LarsKue Apr 26, 2025
d24f5a3
Robustify kwargs passing inference networks, add class variables
stefanradev93 Apr 26, 2025
a43fd07
Merge branch 'dev' of https://github.com/stefanradev93/BayesFlow into…
stefanradev93 Apr 26, 2025
f67e443
Merge branch 'main' into dev
LarsKue Apr 26, 2025
463c0c7
fix convergence method to debug for non-log sinkhorn
LarsKue Apr 26, 2025
8f3739c
Bump optimal transport default to False
stefanradev93 Apr 26, 2025
40eccd4
use logging.info for backend selection instead of logging.debug
LarsKue Apr 26, 2025
8903089
fix model comparison approximator
LarsKue Apr 26, 2025
cbc86b8
improve docs and type hints
LarsKue Apr 26, 2025
77ddc5a
improve One-Sample T-Test Notebook:
LarsKue Apr 26, 2025
ad01171
remove backend print
LarsKue Apr 26, 2025
a742d9c
[skip ci] turn all single-quoted strings into double-quoted strings
LarsKue Apr 26, 2025
b450961
turn all single-quoted strings into double-quoted strings
LarsKue Apr 26, 2025
898a869
Merge remote-tracking branch 'origin/dev' into dev
LarsKue Apr 26, 2025
6fa75da
[no ci] website: list example notebooks only on Examples page
vpratz Apr 27, 2025
5b5363c
ci: update pip via python -m pip
vpratz Apr 27, 2025
a7f9162
Merge pull request #427 from vpratz/docs-migration-advice
vpratz Apr 28, 2025
a322ff1
Adapter keeps track of the transform jacobians (#419)
Kucharssim Apr 29, 2025
5595eab
Deprecate old serialization (`(de)serialize_value_or_type`) and add d…
vpratz Apr 29, 2025
62675c3
Implement Feature for Issue #379: MMD Hypothesis Test (#384)
thegialeo May 2, 2025
3a69644
Add projectors to DeepSet (#453)
han-ol May 3, 2025
ec938ed
[no ci] bf 1.1 to 2.0 notebook: minor additions/edits
vpratz May 4, 2025
ddd4ea8
[no ci] add minor details to FAQ
vpratz May 5, 2025
e8d2f2c
serialization: apply new scheme for package (breaking change) (#457)
vpratz May 5, 2025
42cbbdf
Merge branch 'main' into dev
LarsKue May 5, 2025
335e546
improve adding __version__ attribute
LarsKue May 5, 2025
52bdb58
bump version
LarsKue May 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,25 @@ It provides users and researchers with:
BayesFlow (version 2+) is designed to be a flexible and efficient tool that enables rapid statistical inference
fueled by continuous progress in generative AI and Bayesian inference.

> [!IMPORTANT]
> As the 2.0 version introduced many new features, we still have to make breaking changes from time to time.
> This especially concerns **saving and loading** of models. We aim to stabilize this from the 2.1 release onwards.
> Until then, consider pinning your BayesFlow 2.0 installation to an exact version, or re-training after an update
> for less costly models.

## Important Note for Existing Users

You are currently looking at BayesFlow 2.0+, which is a complete rewrite of the library.
While it shares the same overall goals with the 1.x versions, the API is not compatible.

> [!CAUTION]
> A few features, most notably hierarchical models, have not been ported to BayesFlow 2.0+
> yet. We are working on those features and plan to add them soon. You can find the complete
> list in the [FAQ](#faq) below.

The [Moving from BayesFlow v1.1 to v2.0](examples/From_BayesFlow_1.1_to_2.0.ipynb) guide
highlights how concepts and classes relate between the two versions.

## Conceptual Overview

<div align="center">
Expand Down Expand Up @@ -216,11 +235,48 @@ while the old version was based on TensorFlow.

-------------

**Question:**
Should I switch to BayesFlow 2.0+ now? Are there features that are still missing?

**Answer:**
In general, we recommend to switch, as the new version is easier to use and will continue
to receive improvements and new features. However, a few features are still missing, so you
might want to wait until everything you need has been ported to BayesFlow 2.0+.

Depending on your needs, you might not want to upgrade yet if one of the following applies:

- You have an ongoing project that uses BayesFlow 1.x, and you do not want to allocate
time for migrating it to the new API.
- You have already trained models in BayesFlow 1.x, that you do not want to re-train
with the new version. Loading models from version 1.x in version 2.0+ is not supported.
- You require a feature that was not ported to BayesFlow 2.0+ yet. To our knowledge,
this applies to:
* Two-level/Hierarchical models (planned for version 2.1): `TwoLevelGenerativeModel`, `TwoLevelPrior`.
* Sensitivity analysis (partially discontinued): functionality from the `bayesflow.sensitivity` module. This is still
possible, but we do no longer offer a special module for it. We plan to add a tutorial on this, see [#455](https://github.com/bayesflow-org/bayesflow/issues/455).
* MCMC (discontinued): The `bayesflow.mcmc` module. We are considering other options
to enable the use of BayesFlow in an MCMC setting.
* Networks: `EvidentialNetwork`.
* Model misspecification detection: MMD test in the summary space (see #384).

If you encounter any functionality that is missing and not listed here, please let us
know by opening an issue.

-------------

**Question:**
I still need the old BayesFlow for some of my projects. How can I install it?

**Answer:**
You can find and install the old Bayesflow version via the `stable-legacy` branch on GitHub.
The corresponding [documentation](https://bayesflow.org/stable-legacy/index.html) can be
accessed by selecting the "stable-legacy" entry in the version picker of the documentation.

You can also install the latest version of BayesFlow v1.x from PyPI using

```
pip install "bayesflow<2.0"
```

-------------

Expand Down
12 changes: 3 additions & 9 deletions bayesflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,11 @@ def setup():
"in contexts where you need gradients (e.g. custom training loops)."
)

# dynamically add __version__ attribute
from importlib.metadata import version

# dynamically add version dunder variable
try:
from importlib.metadata import version, PackageNotFoundError
globals()["__version__"] = version("bayesflow")

__version__ = version(__name__)
except PackageNotFoundError:
__version__ = "2.0.0"
finally:
del version
del PackageNotFoundError

# call and clean up namespace
setup()
Expand Down
47 changes: 34 additions & 13 deletions bayesflow/adapters/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from .transforms.filter_transform import Predicate


@serializable
@serializable("bayesflow.adapters")
class Adapter(MutableSequence[Transform]):
"""
Defines an adapter to apply various transforms to data.
Expand Down Expand Up @@ -79,7 +79,9 @@ def get_config(self) -> dict:

return serialize(config)

def forward(self, data: dict[str, any], *, stage: str = "inference", **kwargs) -> dict[str, np.ndarray]:
def forward(
self, data: dict[str, any], *, stage: str = "inference", log_det_jac: bool = False, **kwargs
) -> dict[str, np.ndarray] | tuple[dict[str, np.ndarray], dict[str, np.ndarray]]:
"""Apply the transforms in the forward direction.

Parameters
Expand All @@ -88,22 +90,33 @@ def forward(self, data: dict[str, any], *, stage: str = "inference", **kwargs) -
The data to be transformed.
stage : str, one of ["training", "validation", "inference"]
The stage the function is called in.
log_det_jac: bool, optional
Whether to return the log determinant of the Jacobian of the transforms.
**kwargs : dict
Additional keyword arguments passed to each transform.

Returns
-------
dict
The transformed data.
dict | tuple[dict, dict]
The transformed data or tuple of transformed data and log determinant of the Jacobian.
"""
data = data.copy()
if not log_det_jac:
for transform in self.transforms:
data = transform(data, stage=stage, **kwargs)
return data

log_det_jac = {}
for transform in self.transforms:
data = transform(data, stage=stage, **kwargs)
transformed_data = transform(data, stage=stage, **kwargs)
log_det_jac = transform.log_det_jac(data, log_det_jac, **kwargs)
data = transformed_data

return data
return data, log_det_jac

def inverse(self, data: dict[str, np.ndarray], *, stage: str = "inference", **kwargs) -> dict[str, any]:
def inverse(
self, data: dict[str, np.ndarray], *, stage: str = "inference", log_det_jac: bool = False, **kwargs
) -> dict[str, np.ndarray] | tuple[dict[str, np.ndarray], dict[str, np.ndarray]]:
"""Apply the transforms in the inverse direction.

Parameters
Expand All @@ -112,24 +125,32 @@ def inverse(self, data: dict[str, np.ndarray], *, stage: str = "inference", **kw
The data to be transformed.
stage : str, one of ["training", "validation", "inference"]
The stage the function is called in.
log_det_jac: bool, optional
Whether to return the log determinant of the Jacobian of the transforms.
**kwargs : dict
Additional keyword arguments passed to each transform.

Returns
-------
dict
The transformed data.
dict | tuple[dict, dict]
The transformed data or tuple of transformed data and log determinant of the Jacobian.
"""
data = data.copy()
if not log_det_jac:
for transform in reversed(self.transforms):
data = transform(data, stage=stage, inverse=True, **kwargs)
return data

log_det_jac = {}
for transform in reversed(self.transforms):
data = transform(data, stage=stage, inverse=True, **kwargs)
log_det_jac = transform.log_det_jac(data, log_det_jac, inverse=True, **kwargs)

return data
return data, log_det_jac

def __call__(
self, data: Mapping[str, any], *, inverse: bool = False, stage="inference", **kwargs
) -> dict[str, np.ndarray]:
) -> dict[str, np.ndarray] | tuple[dict[str, np.ndarray], dict[str, np.ndarray]]:
"""Apply the transforms in the given direction.

Parameters
Expand All @@ -145,8 +166,8 @@ def __call__(

Returns
-------
dict
The transformed data.
dict | tuple[dict, dict]
The transformed data or tuple of transformed data and log determinant of the Jacobian.
"""
if inverse:
return self.inverse(data, stage=stage, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion bayesflow/adapters/transforms/as_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .elementwise_transform import ElementwiseTransform


@serializable
@serializable("bayesflow.adapters")
class AsSet(ElementwiseTransform):
"""The `.as_set(["x", "y"])` transform indicates that both `x` and `y` are treated as sets.

Expand Down
2 changes: 1 addition & 1 deletion bayesflow/adapters/transforms/as_time_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .elementwise_transform import ElementwiseTransform


@serializable
@serializable("bayesflow.adapters")
class AsTimeSeries(ElementwiseTransform):
"""The `.as_time_series` transform can be used to indicate that variables shall be treated as time series.

Expand Down
2 changes: 1 addition & 1 deletion bayesflow/adapters/transforms/broadcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .transform import Transform


@serializable
@serializable("bayesflow.adapters")
class Broadcast(Transform):
"""
Broadcasts arrays or scalars to the shape of a given other array.
Expand Down
36 changes: 35 additions & 1 deletion bayesflow/adapters/transforms/concatenate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .transform import Transform


@serializable
@serializable("bayesflow.adapters")
class Concatenate(Transform):
"""Concatenate multiple arrays into a new key. Used to specify how data variables should be treated by the network.

Expand Down Expand Up @@ -115,3 +115,37 @@ def extra_repr(self) -> str:
result += f", axis={self.axis}"

return result

def log_det_jac(
self,
data: dict[str, np.ndarray],
log_det_jac: dict[str, np.ndarray],
*,
strict: bool = False,
inverse: bool = False,
**kwargs,
) -> dict[str, np.ndarray]:
# copy to avoid side effects
log_det_jac = log_det_jac.copy()

if inverse:
if log_det_jac.get(self.into) is not None:
raise ValueError(
"Cannot obtain an inverse Jacobian of concatenation. "
"Transform your variables before you concatenate."
)

return log_det_jac

required_keys = set(self.keys)
available_keys = set(log_det_jac.keys())
common_keys = available_keys & required_keys

if len(common_keys) == 0:
return log_det_jac

parts = [log_det_jac.pop(key) for key in common_keys]

log_det_jac[self.into] = sum(parts)

return log_det_jac
31 changes: 30 additions & 1 deletion bayesflow/adapters/transforms/constrain.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .elementwise_transform import ElementwiseTransform


@serializable
@serializable("bayesflow.adapters")
class Constrain(ElementwiseTransform):
"""
Constrains neural network predictions of a data variable to specified bounds.
Expand Down Expand Up @@ -87,6 +87,11 @@ def constrain(x):

def unconstrain(x):
return inverse_sigmoid((x - lower) / (upper - lower))

def ldj(x):
x = (x - lower) / (upper - lower)
return -np.log(x) - np.log1p(-x) - np.log(upper - lower)

case str() as name:
raise ValueError(f"Unsupported method name for double bounded constraint: '{name}'.")
case other:
Expand All @@ -101,13 +106,22 @@ def constrain(x):

def unconstrain(x):
return inverse_softplus(x - lower)

def ldj(x):
x = x - lower
return x - np.log(np.exp(x) - 1)

case "exp" | "log":

def constrain(x):
return np.exp(x) + lower

def unconstrain(x):
return np.log(x - lower)

def ldj(x):
return -np.log(x - lower)

case str() as name:
raise ValueError(f"Unsupported method name for single bounded constraint: '{name}'.")
case other:
Expand All @@ -122,13 +136,21 @@ def constrain(x):

def unconstrain(x):
return -inverse_softplus(-(x - upper))

def ldj(x):
x = -(x - upper)
return x - np.log(np.exp(x) - 1)

case "exp" | "log":

def constrain(x):
return -np.exp(-x) + upper

def unconstrain(x):
return -np.log(-x + upper)

def ldj(x):
return -np.log(-x + upper)
case str() as name:
raise ValueError(f"Unsupported method name for single bounded constraint: '{name}'.")
case other:
Expand All @@ -142,6 +164,7 @@ def unconstrain(x):

self.constrain = constrain
self.unconstrain = unconstrain
self.ldj = ldj

# do this last to avoid serialization issues
match inclusive:
Expand Down Expand Up @@ -178,3 +201,9 @@ def forward(self, data: np.ndarray, **kwargs) -> np.ndarray:
def inverse(self, data: np.ndarray, **kwargs) -> np.ndarray:
# inverse means network space -> data space, so constrain the data
return self.constrain(data)

def log_det_jac(self, data: np.ndarray, inverse: bool = False, **kwargs) -> np.ndarray:
ldj = self.ldj(data)
if inverse:
ldj = -ldj
return np.sum(ldj, axis=tuple(range(1, ldj.ndim)))
2 changes: 1 addition & 1 deletion bayesflow/adapters/transforms/convert_dtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .elementwise_transform import ElementwiseTransform


@serializable
@serializable("bayesflow.adapters")
class ConvertDType(ElementwiseTransform):
"""
Default transform used to convert all floats from float64 to float32 to be in line with keras framework.
Expand Down
5 changes: 4 additions & 1 deletion bayesflow/adapters/transforms/drop.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .transform import Transform


@serializable
@serializable("bayesflow.adapters")
class Drop(Transform):
"""
Transform to drop variables from further calculation.
Expand Down Expand Up @@ -46,3 +46,6 @@

def extra_repr(self) -> str:
return "[" + ", ".join(map(repr, self.keys)) + "]"

def log_det_jac(self, data: dict[str, any], log_det_jac: dict[str, any], inverse: bool = False, **kwargs):
return self.inverse(data=log_det_jac) if inverse else self.forward(data=log_det_jac)

Check warning on line 51 in bayesflow/adapters/transforms/drop.py

View check run for this annotation

Codecov / codecov/patch

bayesflow/adapters/transforms/drop.py#L51

Added line #L51 was not covered by tests
Loading