|
15 | 15 | )
|
16 | 16 |
|
17 | 17 |
|
| 18 | +@pytest.fixture(scope="session") |
| 19 | +def basic_setup(): |
| 20 | + """Basic setup shared across LC2ST tests.""" |
| 21 | + dim = 2 |
| 22 | + prior = uniform_prior_gaussian_mixture(dim=dim) |
| 23 | + simulator = gaussian_mixture |
| 24 | + return {"dim": dim, "prior": prior, "simulator": simulator} |
| 25 | + |
| 26 | + |
| 27 | +@pytest.fixture(scope="session") |
| 28 | +def npe_factory(basic_setup): |
| 29 | + """Factory for creating NPE models with different training parameters.""" |
| 30 | + |
| 31 | + def _create_npe(num_simulations, max_epochs=None): |
| 32 | + prior = basic_setup["prior"] |
| 33 | + simulator = basic_setup["simulator"] |
| 34 | + |
| 35 | + theta_train = prior.sample((num_simulations,)) |
| 36 | + x_train = simulator(theta_train) |
| 37 | + |
| 38 | + inference = NPE(prior, density_estimator='maf') |
| 39 | + inference = inference.append_simulations(theta=theta_train, x=x_train) |
| 40 | + |
| 41 | + train_kwargs = {"training_batch_size": 100} |
| 42 | + if max_epochs: |
| 43 | + train_kwargs["max_num_epochs"] = max_epochs |
| 44 | + |
| 45 | + return inference.train(**train_kwargs) |
| 46 | + |
| 47 | + return _create_npe |
| 48 | + |
| 49 | + |
| 50 | +@pytest.fixture(scope="session") |
| 51 | +def badly_trained_npe(npe_factory): |
| 52 | + return npe_factory(num_simulations=100, max_epochs=1) |
| 53 | + |
| 54 | + |
| 55 | +@pytest.fixture(scope="session") |
| 56 | +def well_trained_npe(npe_factory): |
| 57 | + return npe_factory(num_simulations=10_000) |
| 58 | + |
| 59 | + |
| 60 | +@pytest.fixture(scope="session") |
| 61 | +def calibration_data(basic_setup, badly_trained_npe): |
| 62 | + """Calibration data for LC2ST tests.""" |
| 63 | + prior = basic_setup["prior"] |
| 64 | + simulator = basic_setup["simulator"] |
| 65 | + npe = badly_trained_npe |
| 66 | + |
| 67 | + num_cal = 100 # Smaller for quick tests |
| 68 | + thetas = prior.sample((num_cal,)) |
| 69 | + xs = simulator(thetas) |
| 70 | + posterior_samples = npe.sample((1,), xs).reshape(-1, thetas.shape[-1]).detach() |
| 71 | + |
| 72 | + return {"thetas": thetas, "xs": xs, "posterior_samples": posterior_samples} |
| 73 | + |
| 74 | + |
18 | 75 | @pytest.mark.parametrize("method", (LC2ST, LC2ST_NF))
|
19 | 76 | @pytest.mark.parametrize("classifier", ('mlp', 'random_forest', MLPClassifier))
|
20 | 77 | @pytest.mark.parametrize("cv_folds", (1, 2))
|
21 | 78 | @pytest.mark.parametrize("num_ensemble", (1, 3))
|
22 | 79 | @pytest.mark.parametrize("z_score", (True, False))
|
23 |
| -def test_running_lc2st(method, classifier, cv_folds, num_ensemble, z_score): |
| 80 | +def test_running_lc2st( |
| 81 | + method, |
| 82 | + classifier, |
| 83 | + cv_folds, |
| 84 | + num_ensemble, |
| 85 | + z_score, |
| 86 | + calibration_data, |
| 87 | + badly_trained_npe, |
| 88 | +): |
24 | 89 | """Tests running inference, LC2ST-(NF) and then getting test quantities."""
|
25 | 90 |
|
26 |
| - num_train = 100 |
27 |
| - num_cal = 100 |
28 | 91 | num_eval = 100
|
29 | 92 | num_trials_null = 2
|
30 | 93 |
|
31 |
| - # task |
32 |
| - dim = 2 |
33 |
| - prior = uniform_prior_gaussian_mixture(dim=dim) |
34 |
| - simulator = gaussian_mixture |
35 |
| - |
36 |
| - # training data for the density estimator |
37 |
| - theta_train = prior.sample((num_train,)) |
38 |
| - x_train = simulator(theta_train) |
39 |
| - |
40 |
| - # Train the neural posterior estimators |
41 |
| - inference = NPE(prior, density_estimator='maf') |
42 |
| - inference = inference.append_simulations(theta=theta_train, x=x_train) |
43 |
| - npe = inference.train(training_batch_size=100, max_num_epochs=1) |
44 |
| - |
45 |
| - # calibration data for the test |
46 |
| - thetas = prior.sample((num_cal,)) |
47 |
| - xs = simulator(thetas) |
48 |
| - posterior_samples = ( |
49 |
| - npe.sample((1,), condition=xs).reshape(-1, thetas.shape[-1]).detach() |
50 |
| - ) |
51 |
| - assert posterior_samples.shape == thetas.shape |
| 94 | + # Get data from fixtures |
| 95 | + thetas = calibration_data["thetas"] |
| 96 | + xs = calibration_data["xs"] |
| 97 | + posterior_samples = calibration_data["posterior_samples"] |
| 98 | + npe = badly_trained_npe |
52 | 99 |
|
53 | 100 | if method == LC2ST:
|
54 | 101 | theta_o = (
|
@@ -107,33 +154,19 @@ def test_running_lc2st(method, classifier, cv_folds, num_ensemble, z_score):
|
107 | 154 |
|
108 | 155 | @pytest.mark.slow
|
109 | 156 | @pytest.mark.parametrize("method", (LC2ST, LC2ST_NF))
|
110 |
| -def test_lc2st_true_positiv_rate(method): |
| 157 | +def test_lc2st_true_positiv_rate(method, basic_setup, badly_trained_npe): |
111 | 158 | """Tests the true positiv rate of the LC2ST-(NF) test:
|
112 | 159 | for a "bad" estimator, the LC2ST-(NF) should reject the null hypothesis."""
|
113 | 160 | num_runs = 100
|
114 | 161 | confidence_level = 0.95
|
115 | 162 |
|
116 |
| - # use small num_train and num_epochs to obtain "bad" estimator |
117 |
| - # (no convergence to the true posterior) |
118 |
| - num_train = 100 |
119 |
| - num_epochs = 2 |
120 |
| - |
121 | 163 | num_cal = 1_000
|
122 | 164 | num_eval = 10_000
|
123 | 165 |
|
124 |
| - # task |
125 |
| - dim = 2 |
126 |
| - prior = uniform_prior_gaussian_mixture(dim=dim) |
127 |
| - simulator = gaussian_mixture |
128 |
| - |
129 |
| - # training data for the density estimator |
130 |
| - theta_train = prior.sample((num_train,)) |
131 |
| - x_train = simulator(theta_train) |
132 |
| - |
133 |
| - # Train the neural posterior estimators |
134 |
| - inference = NPE(prior, density_estimator='maf') |
135 |
| - inference = inference.append_simulations(theta=theta_train, x=x_train) |
136 |
| - npe = inference.train(training_batch_size=100, max_num_epochs=num_epochs) |
| 166 | + # Get data from fixtures |
| 167 | + prior = basic_setup["prior"] |
| 168 | + simulator = basic_setup["simulator"] |
| 169 | + npe = badly_trained_npe |
137 | 170 |
|
138 | 171 | thetas = prior.sample((num_cal,))
|
139 | 172 | xs = simulator(thetas)
|
@@ -186,32 +219,19 @@ def test_lc2st_true_positiv_rate(method):
|
186 | 219 |
|
187 | 220 | @pytest.mark.slow
|
188 | 221 | @pytest.mark.parametrize("method", (LC2ST, LC2ST_NF))
|
189 |
| -def test_lc2st_false_positiv_rate(method, set_seed): |
| 222 | +def test_lc2st_false_positiv_rate(method, basic_setup, well_trained_npe, set_seed): |
190 | 223 | """Tests the false positiv rate of the LC2ST-(NF) test:
|
191 | 224 | for a "good" estimator, the LC2ST-(NF) should not reject the null hypothesis."""
|
192 | 225 | num_runs = 100
|
193 | 226 | confidence_level = 0.95
|
194 | 227 |
|
195 |
| - # use big num_train and num_epochs to obtain "good" estimator |
196 |
| - # (convergence of the estimator) |
197 |
| - num_train = 10_000 |
198 |
| - |
199 | 228 | num_cal = 1_000
|
200 | 229 | num_eval = 10_000
|
201 | 230 |
|
202 |
| - # task |
203 |
| - dim = 2 |
204 |
| - prior = uniform_prior_gaussian_mixture(dim=dim) |
205 |
| - simulator = gaussian_mixture |
206 |
| - |
207 |
| - # training data for the density estimator |
208 |
| - theta_train = prior.sample((num_train,)) |
209 |
| - x_train = simulator(theta_train) |
210 |
| - |
211 |
| - # Train the neural posterior estimators |
212 |
| - inference = NPE(prior, density_estimator='maf') |
213 |
| - inference = inference.append_simulations(theta=theta_train, x=x_train) |
214 |
| - npe = inference.train(training_batch_size=100) |
| 231 | + # Get data from fixtures |
| 232 | + prior = basic_setup["prior"] |
| 233 | + simulator = basic_setup["simulator"] |
| 234 | + npe = well_trained_npe |
215 | 235 |
|
216 | 236 | thetas = prior.sample((num_cal,))
|
217 | 237 | xs = simulator(thetas)
|
|
0 commit comments