def test_c2st_multi_round_snl_on_linearGaussian(num_trials: int): """Test SNL on linear Gaussian, comparing to ground truth posterior via c2st.""" num_dim = 2 x_o = zeros((num_trials, num_dim)) num_samples = 500 num_simulations_per_round = 600 * num_trials # likelihood_mean will be likelihood_shift+theta likelihood_shift = -1.0 * ones(num_dim) likelihood_cov = 0.3 * eye(num_dim) prior_mean = zeros(num_dim) prior_cov = eye(num_dim) prior = MultivariateNormal(loc=prior_mean, covariance_matrix=prior_cov) gt_posterior = true_posterior_linear_gaussian_mvn_prior( x_o, likelihood_shift, likelihood_cov, prior_mean, prior_cov) target_samples = gt_posterior.sample((num_samples, )) simulator, prior = prepare_for_sbi( lambda theta: linear_gaussian(theta, likelihood_shift, likelihood_cov), prior) inference = SNLE(show_progress_bars=False) theta, x = simulate_for_sbi(simulator, prior, num_simulations_per_round, simulation_batch_size=50) likelihood_estimator = inference.append_simulations(theta, x).train() potential_fn, theta_transform = likelihood_estimator_based_potential( prior=prior, likelihood_estimator=likelihood_estimator, x_o=x_o) posterior1 = MCMCPosterior( proposal=prior, potential_fn=potential_fn, theta_transform=theta_transform, thin=5, num_chains=20, ) theta, x = simulate_for_sbi(simulator, posterior1, num_simulations_per_round, simulation_batch_size=50) likelihood_estimator = inference.append_simulations(theta, x).train() potential_fn, theta_transform = likelihood_estimator_based_potential( prior=prior, likelihood_estimator=likelihood_estimator, x_o=x_o) posterior = MCMCPosterior( proposal=prior, potential_fn=potential_fn, theta_transform=theta_transform, thin=5, num_chains=20, ) samples = posterior.sample(sample_shape=(num_samples, )) # Check performance based on c2st accuracy. check_c2st(samples, target_samples, alg="multi-round-snl")
def mdn_inference_with_different_methods(method): num_dim = 2 x_o = torch.tensor([[1.0, 0.0]]) num_samples = 500 num_simulations = 2000 # likelihood_mean will be likelihood_shift+theta likelihood_shift = -1.0 * ones(num_dim) likelihood_cov = 0.3 * eye(num_dim) prior_mean = zeros(num_dim) prior_cov = eye(num_dim) prior = MultivariateNormal(loc=prior_mean, covariance_matrix=prior_cov) gt_posterior = true_posterior_linear_gaussian_mvn_prior( x_o[0], likelihood_shift, likelihood_cov, prior_mean, prior_cov) target_samples = gt_posterior.sample((num_samples, )) def simulator(theta: Tensor) -> Tensor: return linear_gaussian(theta, likelihood_shift, likelihood_cov) simulator, prior = prepare_for_sbi(simulator, prior) inference = method(density_estimator="mdn") theta, x = simulate_for_sbi(simulator, prior, num_simulations) estimator = inference.append_simulations(theta, x).train() if method == SNPE: posterior = DirectPosterior(posterior_estimator=estimator, prior=prior) else: potential_fn, theta_transform = likelihood_estimator_based_potential( likelihood_estimator=estimator, prior=prior, x_o=x_o) posterior = MCMCPosterior(potential_fn=potential_fn, theta_transform=theta_transform, proposal=prior) samples = posterior.sample((num_samples, ), x=x_o) # Compute the c2st and assert it is near chance level of 0.5. check_c2st(samples, target_samples, alg=f"{method}")
def test_api_snl_on_linearGaussian(num_dim: int): """Test API for inference on linear Gaussian model using SNL. Avoids expensive computations by training on few simulations and generating few posterior samples. Args: num_dim: parameter dimension of the gaussian model """ num_samples = 10 prior_mean = zeros(num_dim) prior_cov = eye(num_dim) prior = MultivariateNormal(loc=prior_mean, covariance_matrix=prior_cov) simulator, prior = prepare_for_sbi(diagonal_linear_gaussian, prior) density_estimator = likelihood_nn("maf", num_transforms=3) inference = SNLE(density_estimator=density_estimator, show_progress_bars=False) theta, x = simulate_for_sbi(simulator, prior, 1000, simulation_batch_size=50) likelihood_estimator = inference.append_simulations( theta, x).train(training_batch_size=100) for num_trials in [1, 2]: x_o = zeros((num_trials, num_dim)) potential_fn, theta_transform = likelihood_estimator_based_potential( prior=prior, likelihood_estimator=likelihood_estimator, x_o=x_o) posterior = MCMCPosterior( proposal=prior, potential_fn=potential_fn, theta_transform=theta_transform, thin=3, ) posterior.sample(sample_shape=(num_samples, ))
def test_mnle_api(sampler): # Generate mixed data. num_simulations = 100 theta = torch.rand(num_simulations, 2) x = torch.cat( (torch.rand(num_simulations, 1), torch.randint(0, 2, (num_simulations, 1))), dim=1, ) # Train and infer. prior = BoxUniform(torch.zeros(2), torch.ones(2)) x_o = x[0] # Build estimator manually. density_estimator = likelihood_nn(model="mnle", **dict(tail_bound=2.0)) trainer = MNLE(density_estimator=density_estimator) mnle = trainer.append_simulations(theta, x).train(max_num_epochs=1) # Test different samplers. posterior = trainer.build_posterior(prior=prior, sample_with=sampler) posterior.set_default_x(x_o) if sampler == "vi": posterior.train() posterior.sample((1, ), show_progress_bars=False) # MNLE should work with the default potential as well. potential_fn, parameter_transform = likelihood_estimator_based_potential( mnle, prior, x_o) posterior = MCMCPosterior( potential_fn, proposal=prior, theta_transform=parameter_transform, init_strategy="proposal", ) posterior.sample((1, ), show_progress_bars=False)
def test_inference_with_2d_x(embedding, method): num_dim = 2 num_samples = 10 num_simulations = 100 prior = utils.BoxUniform(zeros(num_dim), torch.ones(num_dim)) simulator, prior = prepare_for_sbi(simulator_2d, prior) theta_o = torch.ones(1, num_dim) if method == SNPE: net_provider = utils.posterior_nn( model="mdn", embedding_net=embedding(), ) num_trials = 1 elif method == SNLE: net_provider = utils.likelihood_nn(model="mdn", embedding_net=embedding()) num_trials = 2 else: net_provider = utils.classifier_nn( model="mlp", z_score_theta="structured", # Test that structured z-scoring works. embedding_net_x=embedding(), ) num_trials = 2 if method == SNRE: inference = method(classifier=net_provider, show_progress_bars=False) else: inference = method(density_estimator=net_provider, show_progress_bars=False) theta, x = simulate_for_sbi(simulator, prior, num_simulations) estimator = inference.append_simulations(theta, x).train(training_batch_size=100, max_num_epochs=10) x_o = simulator(theta_o.repeat(num_trials, 1)) if method == SNLE: potential_fn, theta_transform = likelihood_estimator_based_potential( estimator, prior, x_o) elif method == SNPE: potential_fn, theta_transform = posterior_estimator_based_potential( estimator, prior, x_o) elif method == SNRE: potential_fn, theta_transform = ratio_estimator_based_potential( estimator, prior, x_o) else: raise NotImplementedError posterior = MCMCPosterior( potential_fn=potential_fn, theta_transform=theta_transform, proposal=prior, method="slice_np_vectorized", num_chains=2, ) posterior.potential( posterior.sample((num_samples, ), show_progress_bars=False))
def test_c2st_snl_on_linearGaussian(): """Test whether SNL infers well a simple example with available ground truth. This example has different number of parameters theta than number of x. This test also acts as the only functional test for SNL not marked as slow. """ theta_dim = 3 x_dim = 2 discard_dims = theta_dim - x_dim x_o = zeros(1, x_dim) num_samples = 1000 num_simulations = 3100 # likelihood_mean will be likelihood_shift+theta likelihood_shift = -1.0 * ones(x_dim) likelihood_cov = 0.3 * eye(x_dim) prior_mean = zeros(theta_dim) prior_cov = eye(theta_dim) prior = MultivariateNormal(loc=prior_mean, covariance_matrix=prior_cov) target_samples = samples_true_posterior_linear_gaussian_mvn_prior_different_dims( x_o, likelihood_shift, likelihood_cov, prior_mean, prior_cov, num_discarded_dims=discard_dims, num_samples=num_samples, ) simulator, prior = prepare_for_sbi( lambda theta: linear_gaussian(theta, likelihood_shift, likelihood_cov, num_discarded_dims=discard_dims), prior, ) density_estimator = likelihood_nn("maf", num_transforms=3) inference = SNLE(density_estimator=density_estimator, show_progress_bars=False) theta, x = simulate_for_sbi(simulator, prior, num_simulations, simulation_batch_size=50) likelihood_estimator = inference.append_simulations(theta, x).train() potential_fn, theta_transform = likelihood_estimator_based_potential( prior=prior, likelihood_estimator=likelihood_estimator, x_o=x_o) posterior = MCMCPosterior( proposal=prior, potential_fn=potential_fn, theta_transform=theta_transform, method="slice_np_vectorized", num_chains=5, thin=10, ) samples = posterior.sample((num_samples, )) # Compute the c2st and assert it is near chance level of 0.5. check_c2st(samples, target_samples, alg="snle_a")
def test_api_snl_sampling_methods(sampling_method: str, prior_str: str, init_strategy: str): """Runs SNL on linear Gaussian and tests sampling from posterior via mcmc. Args: mcmc_method: which mcmc method to use for sampling prior_str: use gaussian or uniform prior """ num_dim = 2 num_samples = 10 num_trials = 2 num_simulations = 1000 x_o = zeros((num_trials, num_dim)) # Test for multiple chains is cheap when vectorized. num_chains = 3 if sampling_method == "slice_np_vectorized" else 1 if sampling_method == "rejection": sample_with = "rejection" elif ("slice" in sampling_method or "nuts" in sampling_method or "hmc" in sampling_method): sample_with = "mcmc" else: sample_with = "vi" if prior_str == "gaussian": prior = MultivariateNormal(loc=zeros(num_dim), covariance_matrix=eye(num_dim)) else: prior = utils.BoxUniform(-1.0 * ones(num_dim), ones(num_dim)) simulator, prior = prepare_for_sbi(diagonal_linear_gaussian, prior) inference = SNLE(show_progress_bars=False) theta, x = simulate_for_sbi(simulator, prior, num_simulations, simulation_batch_size=1000) likelihood_estimator = inference.append_simulations( theta, x).train(max_num_epochs=5) potential_fn, theta_transform = likelihood_estimator_based_potential( prior=prior, likelihood_estimator=likelihood_estimator, x_o=x_o) if sample_with == "rejection": posterior = RejectionPosterior(potential_fn=potential_fn, proposal=prior) elif ("slice" in sampling_method or "nuts" in sampling_method or "hmc" in sampling_method): posterior = MCMCPosterior( potential_fn, proposal=prior, theta_transform=theta_transform, method=sampling_method, thin=3, num_chains=num_chains, init_strategy=init_strategy, ) else: posterior = VIPosterior(potential_fn, theta_transform=theta_transform, vi_method=sampling_method) posterior.train(max_num_iters=10) posterior.sample(sample_shape=(num_samples, ))
def test_c2st_and_map_snl_on_linearGaussian_different(num_dim: int, prior_str: str): """Test SNL on linear Gaussian, comparing to ground truth posterior via c2st. Args: num_dim: parameter dimension of the gaussian model prior_str: one of "gaussian" or "uniform" """ num_samples = 500 num_simulations = 3000 trials_to_test = [1] # likelihood_mean will be likelihood_shift+theta likelihood_shift = -1.0 * ones(num_dim) # Use increased cov to avoid too small posterior cov for many trials. likelihood_cov = 0.8 * eye(num_dim) if prior_str == "gaussian": prior_mean = zeros(num_dim) prior_cov = eye(num_dim) prior = MultivariateNormal(loc=prior_mean, covariance_matrix=prior_cov) else: prior = utils.BoxUniform(-2.0 * ones(num_dim), 2.0 * ones(num_dim)) simulator, prior = prepare_for_sbi( lambda theta: linear_gaussian(theta, likelihood_shift, likelihood_cov), prior) density_estimator = likelihood_nn("maf", num_transforms=3) inference = SNLE(density_estimator=density_estimator, show_progress_bars=False) theta, x = simulate_for_sbi(simulator, prior, num_simulations, simulation_batch_size=10000) likelihood_estimator = inference.append_simulations(theta, x).train() # Test inference amortized over trials. for num_trials in trials_to_test: x_o = zeros((num_trials, num_dim)) if prior_str == "gaussian": gt_posterior = true_posterior_linear_gaussian_mvn_prior( x_o, likelihood_shift, likelihood_cov, prior_mean, prior_cov) target_samples = gt_posterior.sample((num_samples, )) elif prior_str == "uniform": target_samples = samples_true_posterior_linear_gaussian_uniform_prior( x_o, likelihood_shift, likelihood_cov, prior=prior, num_samples=num_samples, ) else: raise ValueError(f"Wrong prior_str: '{prior_str}'.") potential_fn, theta_transform = likelihood_estimator_based_potential( prior=prior, likelihood_estimator=likelihood_estimator, x_o=x_o) posterior = MCMCPosterior( proposal=prior, potential_fn=potential_fn, theta_transform=theta_transform, method="slice_np_vectorized", thin=5, num_chains=5, ) samples = posterior.sample(sample_shape=(num_samples, )) # Check performance based on c2st accuracy. check_c2st(samples, target_samples, alg=f"snle_a-{prior_str}-prior-{num_trials}-trials") map_ = posterior.map(num_init_samples=1_000, init_method="proposal", show_progress_bars=False) # TODO: we do not have a test for SNL log_prob(). This is because the output # TODO: density is not normalized, so KLd does not make sense. if prior_str == "uniform": # Check whether the returned probability outside of the support is zero. posterior_prob = get_prob_outside_uniform_prior( posterior, prior, num_dim) assert ( posterior_prob == 0.0 ), "The posterior probability outside of the prior support is not zero" assert ((map_ - ones(num_dim))**2).sum() < 0.5 else: assert ((map_ - gt_posterior.mean)**2).sum() < 0.5
def test_training_and_mcmc_on_device( method, model, data_device, mcmc_method, training_device, prior_device, prior_type="gaussian", ): """Test training on devices. This test does not check training speeds. """ num_dim = 2 num_samples = 10 num_simulations = 100 max_num_epochs = 5 x_o = zeros(1, num_dim).to(data_device) likelihood_shift = -1.0 * ones(num_dim).to(prior_device) likelihood_cov = 0.3 * eye(num_dim).to(prior_device) if prior_type == "gaussian": prior_mean = zeros(num_dim).to(prior_device) prior_cov = eye(num_dim).to(prior_device) prior = MultivariateNormal(loc=prior_mean, covariance_matrix=prior_cov) else: prior = BoxUniform( low=-2 * torch.ones(num_dim), high=2 * torch.ones(num_dim), device=prior_device, ) def simulator(theta): return linear_gaussian(theta, likelihood_shift, likelihood_cov) training_device = process_device(training_device) if method in [SNPE_A, SNPE_C]: kwargs = dict( density_estimator=utils.posterior_nn(model=model, num_transforms=2) ) elif method == SNLE: kwargs = dict( density_estimator=utils.likelihood_nn(model=model, num_transforms=2) ) elif method in (SNRE_A, SNRE_B): kwargs = dict(classifier=utils.classifier_nn(model=model)) else: raise ValueError() inferer = method(show_progress_bars=False, device=training_device, **kwargs) proposals = [prior] # Test for two rounds. for _ in range(2): theta, x = simulate_for_sbi(simulator, proposals[-1], num_simulations) theta, x = theta.to(data_device), x.to(data_device) estimator = inferer.append_simulations(theta, x).train( training_batch_size=100, max_num_epochs=max_num_epochs ) if method == SNLE: potential_fn, theta_transform = likelihood_estimator_based_potential( estimator, prior, x_o ) elif method == SNPE_A or method == SNPE_C: potential_fn, theta_transform = posterior_estimator_based_potential( estimator, prior, x_o ) elif method == SNRE_A or method == SNRE_B: potential_fn, theta_transform = ratio_estimator_based_potential( estimator, prior, x_o ) else: raise ValueError if mcmc_method == "rejection": posterior = RejectionPosterior( proposal=prior, potential_fn=potential_fn, device=training_device, ) elif mcmc_method == "direct": posterior = DirectPosterior( posterior_estimator=estimator, prior=prior ).set_default_x(x_o) else: posterior = MCMCPosterior( potential_fn=potential_fn, theta_transform=theta_transform, proposal=prior, method=mcmc_method, device=training_device, ) proposals.append(posterior) # Check for default device for inference object weights_device = next(inferer._neural_net.parameters()).device assert torch.device(training_device) == weights_device samples = proposals[-1].sample(sample_shape=(num_samples,)) proposals[-1].potential(samples)