Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ For docstrings and comments, we use [Google Style](http://google.github.io/style

**[black](https://github.com/psf/black)**: Automatic code formatting for Python. You can run black manually from the console using `black .` in the top directory of the repository, which will format all files.

**[isort](https://github.com/timothycrosley/isort)**: Used to consistently order imports. You can run isort manually from the console using `isort -y` in the top directory.
**[isort](https://github.com/timothycrosley/isort)**: Used to consistently order imports. You can run isort manually from the console using `isort .` in the top directory.
2 changes: 1 addition & 1 deletion sbibm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sbibm.__version__ import __version__
from sbibm.tasks import get_available_tasks, get_task, get_task_name_display
from sbibm.utils.logging import get_logger
from sbibm.utils.io import get_results
from sbibm.utils.logging import get_logger
2 changes: 1 addition & 1 deletion sbibm/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from sbibm.algorithms.sbi.mcabc import run as mcabc
from sbibm.algorithms.sbi.snpe import run as snpe
from sbibm.algorithms.sbi.smcabc import run as smcabc
from sbibm.algorithms.sbi.snle import run as snle
from sbibm.algorithms.sbi.snpe import run as snpe
from sbibm.algorithms.sbi.snre import run as snre

rej_abc = mcabc
Expand Down
2 changes: 1 addition & 1 deletion sbibm/algorithms/elfi/bolfi.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def run(
num_warmup: int = 1000,
) -> (torch.Tensor, int, Optional[torch.Tensor]):
"""Runs BOLFI from elfi package

Args:
task: Task instance
num_samples: Number of samples to generate from posterior
Expand Down
12 changes: 10 additions & 2 deletions sbibm/algorithms/elfi/utils/prior.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ def build_prior(task: Task, model: elfi.ElfiModel):
scale = np.sqrt(prior_params["C"][dim, dim])

elfi.Prior(
"norm", loc, scale, model=model, name=f"parameter_{dim}",
"norm",
loc,
scale,
model=model,
name=f"parameter_{dim}",
)

bounds[f"parameter_{dim}"] = (
Expand All @@ -48,7 +52,11 @@ def build_prior(task: Task, model: elfi.ElfiModel):
scale = prior_params["high"][dim] - loc

elfi.Prior(
"uniform", loc, scale, model=model, name=f"parameter_{dim}",
"uniform",
loc,
scale,
model=model,
name=f"parameter_{dim}",
)

bounds[f"parameter_{dim}"] = (
Expand Down
12 changes: 6 additions & 6 deletions sbibm/algorithms/pyabc/pyabc_utils.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import logging
from typing import Callable, Dict, Tuple, Optional
from typing import Callable, Dict, Optional, Tuple

import numpy as np
import pyabc
import torch
import sbibm

from sbi.inference import MCABC

import sbibm
from sbibm.tasks.task import Task


class PyAbcSimulator:
"""Wrapper from sbibm task to pyABC.
"""Wrapper from sbibm task to pyABC.

pyABC defines its own priors and they are sampled without batch dimension. This
wrapper defines a call method that takes a single parameter set from a pyABC prior
and uses the sbibm task simulator to generate the corresponding data and to return
it in pyABC format.
it in pyABC format.
"""

def __init__(self, task):
Expand Down Expand Up @@ -151,7 +151,7 @@ def run_pyabc(
use_last_pop_samples: bool = False,
) -> Tuple[torch.Tensor, torch.Tensor]:
"""Run pyabc SMC with fixed budget and return particles and weights.

Return previous population or prior samples if budget is exceeded.
"""
log = sbibm.get_logger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions sbibm/algorithms/pyabc/smcabc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import torch

import sbibm
from sbibm.algorithms.sbi.utils import get_sass_transform, run_lra, clip_int
from sbibm.algorithms.sbi.utils import clip_int, get_sass_transform, run_lra
from sbibm.tasks.task import Task
from sbibm.utils.kde import get_kde
from sbibm.utils.torch import sample_with_weights
Expand All @@ -18,8 +18,8 @@
PyAbcSimulator,
get_distance,
run_pyabc,
wrap_prior,
run_rejection_abc,
wrap_prior,
)


Expand Down
2 changes: 1 addition & 1 deletion sbibm/algorithms/pyro/mcmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def run(
Produces `num_samples` while accounting for warmup (burn-in) and thinning.

Note that the actual number of simulations is not controlled for with MCMC since
algorithms are only used as a reference method in the benchmark.
algorithms are only used as a reference method in the benchmark.

MCMC is run on the potential function, which returns the unnormalized
negative log posterior probability. Note that this requires a tractable likelihood.
Expand Down
11 changes: 7 additions & 4 deletions sbibm/algorithms/pyro/utils/tensorboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ def tb_acf(writer, mcmc, site_name="parameters", num_samples=1000, maxlags=50):
fig = plt.figure()
plt.gca().acorr(samples[c, :].squeeze()[:, p].numpy(), maxlags=maxlags)
writer.add_figure(
f"acf/chain {c+1}/parameter {p+1}", fig, close=True,
f"acf/chain {c+1}/parameter {p+1}",
fig,
close=True,
)


Expand All @@ -39,13 +41,14 @@ def tb_marginals(writer, mcmc, site_name="parameters", num_samples=1000):
for c in range(samples.shape[0]):
for p in range(samples.shape[-1]):
writer.add_histogram(
f"marginal/{site_name}/{p+1}", samples[c, :].squeeze()[:, p], c,
f"marginal/{site_name}/{p+1}",
samples[c, :].squeeze()[:, p],
c,
)


def tb_make_hook_fn(writer, site_name="parameters"):
"""Builds hook function for runtime logging
"""
"""Builds hook function for runtime logging"""

def hook_fn(kernel, samples, stage, i):
"""Logging during run
Expand Down
6 changes: 5 additions & 1 deletion sbibm/algorithms/pytorch/baseline_prior.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
from sbibm.tasks.task import Task


def run(task: Task, num_samples: int, **kwargs: Any,) -> torch.Tensor:
def run(
task: Task,
num_samples: int,
**kwargs: Any,
) -> torch.Tensor:
"""Random samples from prior as baseline

Args:
Expand Down
1 change: 1 addition & 0 deletions sbibm/algorithms/sbi/mcabc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from sbibm.tasks.task import Task
from sbibm.utils.io import save_tensor_to_csv
from sbibm.utils.kde import get_kde

from .utils import get_sass_transform, run_lra


Expand Down
13 changes: 7 additions & 6 deletions sbibm/algorithms/sbi/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import numpy as np
import torch

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from torch.distributions.transformed_distribution import TransformedDistribution

from sbibm.utils.nflows import FlowWrapper
Expand Down Expand Up @@ -47,10 +46,10 @@ def clip_int(value, minimum, maximum):
def get_sass_transform(theta, x, expansion_degree=1, sample_weight=None):
"""Return semi-automatic summary statitics function.

Running weighted linear regressin as in
Running weighted linear regressin as in
Fearnhead & Prandle 2012: https://arxiv.org/abs/1004.1112
Following implementation in

Following implementation in
https://abcpy.readthedocs.io/en/latest/_modules/abcpy/statistics.html#Identity
and
https://pythonhosted.org/abcpy/_modules/abcpy/summaryselections.html#Semiautomatic
Expand Down Expand Up @@ -89,7 +88,9 @@ def run_lra(
for parameter_idx in range(theta.shape[1]):
regression_model = LinearRegression(fit_intercept=True)
regression_model.fit(
X=x, y=theta[:, parameter_idx], sample_weight=sample_weight,
X=x,
y=theta[:, parameter_idx],
sample_weight=sample_weight,
)
theta_adjusted[:, parameter_idx] += regression_model.predict(
observation.reshape(1, -1)
Expand Down
11 changes: 8 additions & 3 deletions sbibm/metrics/c2st.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def c2st(
n_folds: Number of folds
z_score: Z-scoring using X
noise_scale: If passed, will add Gaussian noise with std noise_scale to samples

References:
[1]: https://scikit-learn.org/stable/modules/cross_validation.html
"""
Expand Down Expand Up @@ -56,7 +56,12 @@ def c2st(
)

data = np.concatenate((X, Y))
target = np.concatenate((np.zeros((X.shape[0],)), np.ones((Y.shape[0],)),))
target = np.concatenate(
(
np.zeros((X.shape[0],)),
np.ones((Y.shape[0],)),
)
)

shuffle = KFold(n_splits=n_folds, shuffle=True, random_state=seed)
scores = cross_val_score(clf, data, target, cv=shuffle, scoring=scoring)
Expand Down Expand Up @@ -84,7 +89,7 @@ def c2st_auc(
n_folds: Number of folds
z_score: Z-scoring using X
noise_scale: If passed, will add Gaussian noise with std noise_scale to samples

Returns:
Metric
"""
Expand Down
12 changes: 5 additions & 7 deletions sbibm/metrics/ksd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

import numpy as np
import torch
from sbibm.third_party.kgof.kernel import KGauss
from sbibm.third_party.kgof.goftest import KernelSteinTest, bootstrapper_rademacher
from sbibm.third_party.kgof.util import meddistance

from sbibm.tasks.task import Task
from sbibm.third_party.kgof.goftest import KernelSteinTest, bootstrapper_rademacher
from sbibm.third_party.kgof.kernel import KGauss
from sbibm.third_party.kgof.util import meddistance
from sbibm.utils.torch import get_default_device

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -114,8 +114,7 @@ def ksd_gaussian_kernel(

class DataWrapped:
def __init__(self, data):
"""Wraps `data` such that it can be used with `kgof`
"""
"""Wraps `data` such that it can be used with `kgof`"""
self._data = data

def data(self):
Expand All @@ -124,8 +123,7 @@ def data(self):

class UnnormalizedDensityWrapped:
def __init__(self, log_prob_grad: Callable):
"""Wraps `log_prob_grad` function such that it can be used with `kgof`
"""
"""Wraps `log_prob_grad` function such that it can be used with `kgof`"""
self.log_prob_grad = log_prob_grad

def grad_log(self, X: np.ndarray) -> np.ndarray:
Expand Down
6 changes: 5 additions & 1 deletion sbibm/metrics/mvn_kl.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import torch


def mvn_kl_pq(X: torch.Tensor, Y: torch.Tensor, z_score: bool = True,) -> torch.Tensor:
def mvn_kl_pq(
X: torch.Tensor,
Y: torch.Tensor,
z_score: bool = True,
) -> torch.Tensor:
"""KL(p||q) between Multivariate Normal distributions

X and Y are both sets of samples, the mean and covariance of which is estimated
Expand Down
3 changes: 2 additions & 1 deletion sbibm/metrics/ppc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@


def median_distance(
predictive_samples: torch.Tensor, observation: torch.Tensor,
predictive_samples: torch.Tensor,
observation: torch.Tensor,
) -> torch.Tensor:
"""Compute median distance

Expand Down
14 changes: 7 additions & 7 deletions sbibm/tasks/bernoulli_glm/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@

class BernoulliGLM(Task):
def __init__(self, summary="sufficient"):
"""Bernoulli GLM
"""
"""Bernoulli GLM"""
self.summary = summary
if self.summary == "sufficient":
dim_data = 10
Expand Down Expand Up @@ -67,8 +66,8 @@ def get_simulator(self, max_calls: Optional[int] = None) -> Simulator:
"""Get function returning samples from simulator given parameters

Args:
max_calls: Maximum number of function calls. Additional calls will
result in SimulationBudgetExceeded exceptions. Defaults to None
max_calls: Maximum number of function calls. Additional calls will
result in SimulationBudgetExceeded exceptions. Defaults to None
for infinite budget

Return:
Expand Down Expand Up @@ -116,8 +115,7 @@ def simulator(
return Simulator(task=self, simulator=simulator, max_calls=max_calls)

def get_observation(self, num_observation: int) -> torch.Tensor:
"""Get observed data for a given observation number
"""
"""Get observed data for a given observation number"""
if not self.raw:
path = (
self.path
Expand Down Expand Up @@ -146,7 +144,9 @@ def flatten_data(self, data: torch.Tensor) -> torch.Tensor:
return data.reshape(-1, self.dim_data)

def _sample_reference_posterior(
self, num_samples: int, num_observation: Optional[int] = None,
self,
num_samples: int,
num_observation: Optional[int] = None,
) -> torch.Tensor:
from pypolyagamma import PyPolyaGamma
from tqdm import tqdm
Expand Down
8 changes: 5 additions & 3 deletions sbibm/tasks/gaussian_linear/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ def _get_reference_posterior(
self.simulator_params["precision_matrix"], observation.reshape(-1)
)
+ torch.matmul(
self.prior_params["precision_matrix"], self.prior_params["loc"],
self.prior_params["precision_matrix"],
self.prior_params["loc"],
)
),
)
Expand All @@ -138,12 +139,13 @@ def _sample_reference_posterior(
num_observation: Observation number
observation: Instead of passing an observation number, an observation may be
passed directly

Returns:
Samples from reference posterior
"""
posterior = self._get_reference_posterior(
num_observation=num_observation, observation=observation,
num_observation=num_observation,
observation=observation,
)

return posterior.sample((num_samples,))
Expand Down
9 changes: 5 additions & 4 deletions sbibm/tasks/gaussian_linear_uniform/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ def get_simulator(self, max_calls: Optional[int] = None) -> Simulator:
"""Get function returning samples from simulator given parameters

Args:
max_calls: Maximum number of function calls. Additional calls will
result in SimulationBudgetExceeded exceptions. Defaults to None
max_calls: Maximum number of function calls. Additional calls will
result in SimulationBudgetExceeded exceptions. Defaults to None
for infinite budget

Return:
Expand Down Expand Up @@ -93,7 +93,7 @@ def _sample_reference_posterior(
num_observation: Observation number
observation: Instead of passing an observation number, an observation may be
passed directly

Returns:
Samples from reference posterior
"""
Expand All @@ -108,7 +108,8 @@ def _sample_reference_posterior(
reference_posterior_samples = []

sampling_dist = pdist.MultivariateNormal(
loc=observation, precision_matrix=self.simulator_params["precision_matrix"],
loc=observation,
precision_matrix=self.simulator_params["precision_matrix"],
)

# Reject samples outside of prior bounds
Expand Down
Loading