1919from coupled_rejection_sampling .mvn import coupled_mvns , mvn_logpdf
2020from coupled_rejection_sampling .thorisson import modified_thorisson
2121
22+
2223JAX_KEY = jax .random .PRNGKey (0 )
23- B = 1_000 # number of parallel coupled chains
24- K = 50 # number of experiments
25- CS = np .linspace (0.8 , 0.99 , 5 )
26- NS = [16 , 32 , 64 ]
24+ K = 10_000 # number of experiments
25+ CS = np .linspace (0.8 , 0.99 , 7 )
26+ NS = [4 , 8 , 16 , 32 , 64 , 128 , 256 ]
2727
2828ALPHA = 100. # Same wide prior as in mMALA paper
29- EPS = 0.05
29+ EPS = 1.
3030
31- RUN = True
31+ RUN = False
3232PLOT = True
3333
3434data_path = "data/heart.csv"
3535save_path = "out/mmala.npz"
3636
3737
3838def thorisson_sample (C ):
39+ @jax .jit
3940 def sampler (key , x_mean , x_chol , y_mean , y_chol ):
4041 def p_xy (k , mean , scale ):
4142 return mean + scale @ jax .random .normal (k , (mean .shape [0 ],))
@@ -52,25 +53,26 @@ def p_xy(k, mean, scale):
5253
5354
5455def rejection_sample (N ):
56+ @jax .jit
5557 def sampler (key , x_mean , x_chol , y_mean , y_chol ):
5658 X , Y , coupled , _ = coupled_mvns (key , x_mean , x_chol , y_mean , y_chol , N )
5759 return X , Y , coupled
5860
5961 return sampler
6062
6163
64+ @partial (jax .jit , static_argnums = (2 ,))
6265def _get_manifold_langevin_discretisation (theta , eps , log_pi ):
6366 """Gets the mean and cholesky covariance of the proposal. This only considers flat manifolds"""
6467 d = theta .shape [0 ]
6568
6669 # Compute gradient and Fisher information
67- value , grad = jax .value_and_grad (log_pi )(theta )
70+ grad = jax .grad (log_pi )(theta )
6871 fisher = - jax .hessian (log_pi )(theta )
69-
72+ # id_print(fisher, what="fisher autograd")
7073 # Get sqrt of inverse Fisher
7174 chol_fisher = jlinalg .cholesky (fisher , lower = True )
7275 inv_chol_fisher = jlinalg .solve_triangular (chol_fisher , jnp .eye (d ), lower = True )
73-
7476 # Get mean
7577 mean = 0.5 * eps ** 2 * jlinalg .cho_solve ((chol_fisher , True ), grad )
7678
@@ -101,16 +103,15 @@ def simplified_manifold_mala_step(key, x, y, eps, sampler, log_pi):
101103
102104 x = jax .lax .select (accept_x , x_star , x )
103105 y = jax .lax .select (accept_y , y_star , y )
104-
105106 return x , y , accept_x & accept_y & coupled
106107
107108
108109@partial (jax .jit , static_argnums = (2 , 3 , 4 ))
109110def sample_coupled_chain (key , eps , sampler , log_pi , D ):
110111 key , init_x_key , init_y_key = jax .random .split (key , 3 )
111112
112- x0 = jax .random .normal (init_x_key , (D ,))
113- y0 = jax .random .normal (init_y_key , (D ,))
113+ x0 = 0.1 * jax .random .normal (init_x_key , (D ,))
114+ y0 = 0.1 * jax .random .normal (init_y_key , (D ,))
114115
115116 def cond (carry ):
116117 return ~ carry [- 1 ]
@@ -120,7 +121,6 @@ def body(carry):
120121 op_key , sample_key = jax .random .split (op_key , 2 )
121122 x , y , coupled = simplified_manifold_mala_step (sample_key , x , y , eps , sampler , log_pi )
122123 return op_key , x , y , iteration + 1 , coupled
123-
124124 * _ , meeting_time , _ = jax .lax .while_loop (cond , body , (key , x0 , y0 , 0 , False ))
125125 return meeting_time
126126
@@ -135,59 +135,52 @@ def experiment():
135135
136136 X = np .pad (X , [(0 , 0 ), (0 , 1 )], constant_values = 1 )
137137
138- y = df .values [:, - 1 ].astype (bool )
138+ y = df .values [:, - 1 ].astype (float )
139139
140- def log_target (theta ):
140+ @partial (jax .jit , static_argnames = ("return_fisher" ,))
141+ def log_target (theta , return_fisher = False ):
141142 prior = norm .logpdf (theta , 0. , ALPHA ** 0.5 ).sum ()
143+ temp = X @ theta
144+ log_lik = jnp .dot (y , temp ) - jnp .sum (jax .nn .softplus (temp ))
142145
143- temp = - X @ theta
144- log_probs_true = - jnp .logaddexp (0 , temp )
145- log_probs_false = temp + log_probs_true
146- log_lik = jnp .where (y , log_probs_true , log_probs_false )
147- return prior + jnp .nansum (log_lik )
146+ if not return_fisher :
147+ return log_lik + prior
148148
149- rejection_meeting_times_res = np .empty ((len (NS ), K , B ))
150- thorisson_meeting_times_res = np .empty ((len (CS ), K , B ))
149+ rejection_meeting_times_res = np .empty ((len (NS ), K ))
150+ thorisson_meeting_times_res = np .empty ((len (CS ), K ))
151151
152152 rejection_runtime_res = np .empty ((len (NS ), K ))
153153 thorisson_runtime_res = np .empty ((len (CS ), K ))
154154
155- # Rejection:
156155 rej_key = JAX_KEY
157- for i , N in enumerate (tqdm .tqdm (NS , leave = False )):
156+ for i , N in enumerate (tqdm .tqdm (NS , leave = True )):
158157 rej_sampler = rejection_sample (N )
159- rej_experiment_fun = jax .jit (
160- jax .vmap (lambda op_key : sample_coupled_chain (op_key , EPS , rej_sampler , log_target , dim )))
158+ rej_experiment_fun = jax .jit (lambda op_key : sample_coupled_chain (op_key , EPS , rej_sampler , log_target , dim ))
161159
162160 # run it once to compile
163- batched_keys = jax .random .split (JAX_KEY , B )
164- block = rej_experiment_fun (batched_keys )
161+ block = rej_experiment_fun (rej_key )
165162 block .block_until_ready ()
166- for k in enumerate ( tqdm . trange ( K , leave = False ) ):
163+ for k in range ( K ):
167164 tic = time .time ()
168165 rej_key , subkey = jax .random .split (rej_key )
169- batched_keys = jax .random .split (subkey , B )
170166
171- rej_out = rej_experiment_fun (batched_keys )
167+ rej_out = rej_experiment_fun (rej_key )
172168 rej_out .block_until_ready ()
173169 rejection_meeting_times_res [i , k ] = rej_out
174170 rejection_runtime_res [i , k ] = time .time () - tic
175171
176172 thor_key = JAX_KEY
177- for j , C in enumerate (tqdm .tqdm (CS , leave = False )):
173+ for j , C in enumerate (tqdm .tqdm (CS , leave = True )):
178174 thor_sampler = thorisson_sample (C )
179- thor_experiment_fun = jax .jit (
180- jax .vmap (lambda op_key : sample_coupled_chain (op_key , EPS , thor_sampler , log_target , dim )))
175+ thor_experiment_fun = jax .jit (lambda op_key : sample_coupled_chain (op_key , EPS , thor_sampler , log_target , dim ))
181176
182177 # run it once to compile
183- batched_keys = jax .random .split (JAX_KEY , B )
184- block = thor_experiment_fun (batched_keys )
178+ block = thor_experiment_fun (thor_key )
185179 block .block_until_ready ()
186- for k in tqdm . trange (K ):
180+ for k in range (K ):
187181 tic = time .time ()
188182 thor_key , subkey = jax .random .split (thor_key )
189- batched_keys = jax .random .split (subkey , B )
190- thor_out = thor_experiment_fun (batched_keys )
183+ thor_out = thor_experiment_fun (thor_key )
191184 thor_out .block_until_ready ()
192185 thorisson_meeting_times_res [j , k ] = thor_out
193186 thorisson_runtime_res [j , k ] = time .time () - tic
@@ -205,60 +198,78 @@ def log_target(theta):
205198 cmap = plt .get_cmap ("tab10" )
206199 data = np .load (save_path )
207200
208- fig , axes = plt .subplots (ncols = 2 , figsize = (15 , 6 ), sharey = True )
209-
210- for i , D in enumerate (DS ):
211- axes [0 ].set_title ("Rejection" )
212- axes [0 ].set_xscale ("log" )
213- axes [0 ].set_yscale ("log" )
214- axes [0 ].plot (data ["NS" ], data ["rejection_meeting_times" ][i ].mean (- 1 ).mean (- 1 ),
215- color = cmap (i ), label = f"$D={ D } $" )
216- axes [0 ].fill_between (data ["NS" ],
217- data ["rejection_meeting_times" ][i ].mean (- 1 ).mean (- 1 ) - 1.96 *
218- data ["rejection_meeting_times" ][i ].mean (- 1 ).std (- 1 ),
219- data ["rejection_meeting_times" ][i ].mean (- 1 ).mean (- 1 ) + 1.96 *
220- data ["rejection_meeting_times" ][i ].mean (- 1 ).std (- 1 ),
221- color = cmap (i ), alpha = 0.66 )
222-
223- axes [1 ].set_title ("Thorisson" )
224- axes [1 ].plot (data ["CS" ], data ["thorisson_meeting_times" ][i ].mean (- 1 ).mean (- 1 ),
225- color = cmap (i ), label = f"$D={ D } $" )
226- axes [1 ].fill_between (data ["CS" ],
227- data ["thorisson_meeting_times" ][i ].mean (- 1 ).mean (- 1 ) - 1.96 *
228- data ["thorisson_meeting_times" ][i ].mean (- 1 ).std (- 1 ),
229- data ["thorisson_meeting_times" ][i ].mean (- 1 ).mean (- 1 ) + 1.96 *
230- data ["thorisson_meeting_times" ][i ].mean (- 1 ).std (- 1 ),
231- color = cmap (i ), alpha = 0.66 )
232- axes [1 ].set_yscale ("log" )
233- axes [1 ].xaxis .set_major_formatter (FormatStrFormatter ('%.1f' ))
234- axes [1 ].legend ()
235- tikzplotlib .save ("out/gibbs_meeting_time.tikz" )
236-
237- fig , axes = plt .subplots (ncols = 2 , figsize = (15 , 6 ), sharey = True )
238-
239- for i , D in enumerate (DS ):
240- axes [0 ].set_title ("Rejection" )
241- axes [0 ].set_xscale ("log" )
242- axes [0 ].set_yscale ("log" )
243- axes [0 ].plot (data ["NS" ], data ["rejection_runtime" ][i ].mean (- 1 ),
244- color = cmap (i ), label = f"$D={ D } $" )
245- axes [0 ].fill_between (data ["NS" ],
246- data ["rejection_runtime" ][i ].mean (- 1 ) - 1.96 *
247- data ["rejection_runtime" ][i ].std (- 1 ),
248- data ["rejection_runtime" ][i ].mean (- 1 ) + 1.96 *
249- data ["rejection_runtime" ][i ].std (- 1 ),
250- color = cmap (i ), alpha = 0.66 )
251- axes [1 ].set_title ("Thorisson" )
252- axes [1 ].plot (data ["CS" ], data ["thorisson_runtime" ][i ].mean (- 1 ),
253- color = cmap (i ), label = f"$D={ D } $" )
254- axes [1 ].fill_between (data ["CS" ],
255- data ["thorisson_runtime" ][i ].mean (- 1 ) - 1.96 *
256- data ["thorisson_runtime" ][i ].std (- 1 ),
257- data ["thorisson_runtime" ][i ].mean (- 1 ) + 1.96 *
258- data ["thorisson_runtime" ][i ].std (- 1 ),
259- color = cmap (i ), alpha = 0.66 )
260- axes [1 ].set_yscale ("log" )
261- axes [1 ].xaxis .set_major_formatter (FormatStrFormatter ('%.1f' ))
262- axes [1 ].legend ()
263-
264- tikzplotlib .save ("out/gibbs_run_time.tikz" )
201+ index = pd .MultiIndex .from_product ([["meeting time" , "run time (s)" ], ["mean" , "standard deviation" ]])
202+ thorisson_df = pd .DataFrame (columns = data ["CS" ], index = index )
203+ rejection_df = pd .DataFrame (columns = data ["NS" ], index = index )
204+
205+ thorisson_df .loc [("meeting time" , "mean" )] = [f"${ v .mean (- 1 ):.1f} $" for v in data ["thorisson_meeting_times" ]]
206+ thorisson_df .loc [("run time (s)" , "mean" )] = [f"${ v .mean (- 1 ):.1e} $" for v in data ["thorisson_runtime" ][:, 1 :]]
207+
208+ rejection_df .loc [("meeting time" , "mean" )] = [f"${ v .mean (- 1 ):.1f} $" for v in data ["rejection_meeting_times" ]]
209+ rejection_df .loc [("run time (s)" , "mean" )] = [f"${ v .mean (- 1 ):.1e} $" for v in data ["rejection_runtime" ][:, 1 :]]
210+
211+
212+ thorisson_df .loc [("meeting time" , "standard deviation" )] = [f"${ v .std (- 1 ):.1f} $" for v in data ["thorisson_meeting_times" ]]
213+ thorisson_df .loc [("run time (s)" , "standard deviation" )] = [f"${ v .std (- 1 ):.1e} $" for v in data ["thorisson_runtime" ][:, 1 :]]
214+
215+ rejection_df .loc [("meeting time" , "standard deviation" )] = [f"${ v .std (- 1 ):.1f} $" for v in data ["rejection_meeting_times" ]]
216+ rejection_df .loc [("run time (s)" , "standard deviation" )] = [f"${ v .std (- 1 ):.1e} $" for v in data ["rejection_runtime" ][:, 1 :]]
217+
218+
219+ print (rejection_df .to_latex ("out/rejection_mmala.tex" ))
220+ print (thorisson_df .to_latex ("out/thorisson_mmala.tex" ))
221+ # for i, D in enumerate(DS):
222+ # axes[0].set_title("Rejection")
223+ # axes[0].set_xscale("log")
224+ # axes[0].set_yscale("log")
225+ # axes[0].plot(data["NS"], data["rejection_meeting_times"][i].mean(-1).mean(-1),
226+ # color=cmap(i), label=f"$D={D}$")
227+ # axes[0].fill_between(data["NS"],
228+ # data["rejection_meeting_times"][i].mean(-1).mean(-1) - 1.96 *
229+ # data["rejection_meeting_times"][i].mean(-1).std(-1),
230+ # data["rejection_meeting_times"][i].mean(-1).mean(-1) + 1.96 *
231+ # data["rejection_meeting_times"][i].mean(-1).std(-1),
232+ # color=cmap(i), alpha=0.66)
233+ #
234+ # axes[1].set_title("Thorisson")
235+ # axes[1].plot(data["CS"], data["thorisson_meeting_times"][i].mean(-1).mean(-1),
236+ # color=cmap(i), label=f"$D={D}$")
237+ # axes[1].fill_between(data["CS"],
238+ # data["thorisson_meeting_times"][i].mean(-1).mean(-1) - 1.96 *
239+ # data["thorisson_meeting_times"][i].mean(-1).std(-1),
240+ # data["thorisson_meeting_times"][i].mean(-1).mean(-1) + 1.96 *
241+ # data["thorisson_meeting_times"][i].mean(-1).std(-1),
242+ # color=cmap(i), alpha=0.66)
243+ # axes[1].set_yscale("log")
244+ # axes[1].xaxis.set_major_formatter(FormatStrFormatter('%.1f'))
245+ # axes[1].legend()
246+ # tikzplotlib.save("out/gibbs_meeting_time.tikz")
247+ #
248+ # fig, axes = plt.subplots(ncols=2, figsize=(15, 6), sharey=True)
249+ #
250+ # for i, D in enumerate(DS):
251+ # axes[0].set_title("Rejection")
252+ # axes[0].set_xscale("log")
253+ # axes[0].set_yscale("log")
254+ # axes[0].plot(data["NS"], data["rejection_runtime"][i].mean(-1),
255+ # color=cmap(i), label=f"$D={D}$")
256+ # axes[0].fill_between(data["NS"],
257+ # data["rejection_runtime"][i].mean(-1) - 1.96 *
258+ # data["rejection_runtime"][i].std(-1),
259+ # data["rejection_runtime"][i].mean(-1) + 1.96 *
260+ # data["rejection_runtime"][i].std(-1),
261+ # color=cmap(i), alpha=0.66)
262+ # axes[1].set_title("Thorisson")
263+ # axes[1].plot(data["CS"], data["thorisson_runtime"][i].mean(-1),
264+ # color=cmap(i), label=f"$D={D}$")
265+ # axes[1].fill_between(data["CS"],
266+ # data["thorisson_runtime"][i].mean(-1) - 1.96 *
267+ # data["thorisson_runtime"][i].std(-1),
268+ # data["thorisson_runtime"][i].mean(-1) + 1.96 *
269+ # data["thorisson_runtime"][i].std(-1),
270+ # color=cmap(i), alpha=0.66)
271+ # axes[1].set_yscale("log")
272+ # axes[1].xaxis.set_major_formatter(FormatStrFormatter('%.1f'))
273+ # axes[1].legend()
274+ #
275+ # tikzplotlib.save("out/gibbs_run_time.tikz")
0 commit comments